diff options
author | stanton <stanton> | 1998-09-30 02:19:04 (GMT) |
---|---|---|
committer | stanton <stanton> | 1998-09-30 02:19:04 (GMT) |
commit | da9d3d17d12952676d1c5a7a8424221f708d4a0e (patch) | |
tree | 2ab332f7ff062a2df7010439c8d332e4f71ade6d /generic | |
parent | 139cae1fba039b0ff1c8d5e8f563903d2fd52c72 (diff) | |
download | tk-da9d3d17d12952676d1c5a7a8424221f708d4a0e.zip tk-da9d3d17d12952676d1c5a7a8424221f708d4a0e.tar.gz tk-da9d3d17d12952676d1c5a7a8424221f708d4a0e.tar.bz2 |
Merged 8.0.3 changes into 8.1
Diffstat (limited to 'generic')
88 files changed, 0 insertions, 95947 deletions
diff --git a/generic/README b/generic/README deleted file mode 100644 index 4cbf41e..0000000 --- a/generic/README +++ /dev/null @@ -1,5 +0,0 @@ -This directory contains Tk source files that work on all the platforms -where Tk runs (e.g. UNIX, PCs, and Macintoshes). Platform-specific -sources are in the directories ../unix, ../win, and ../mac. - -RCS ID: @(#) $Id: README,v 1.2 1998/09/14 18:23:02 stanton Exp $ diff --git a/generic/default.h b/generic/default.h deleted file mode 100644 index c83567b..0000000 --- a/generic/default.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * default.h -- - * - * This file defines the defaults for all options for all of - * the Tk widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: default.h,v 1.2 1998/09/14 18:23:02 stanton Exp $ - */ - -#ifndef _DEFAULT -#define _DEFAULT - -#if defined(__WIN32__) || defined(_WIN32) -# include "tkWinDefault.h" -#else -# if defined(MAC_TCL) -# include "tkMacDefault.h" -# else -# include "tkUnixDefault.h" -# endif -#endif - -#endif /* _DEFAULT */ diff --git a/generic/ks_names.h b/generic/ks_names.h deleted file mode 100644 index 0bc0e13..0000000 --- a/generic/ks_names.h +++ /dev/null @@ -1,921 +0,0 @@ -/* - * This file is generated from $(INCLUDESRC)/keysymdef.h. Do not edit. - * RCS: $Id: ks_names.h,v 1.3 1998/09/14 18:23:02 stanton Exp $ - */ -{ "BackSpace", 0xFF08 }, -{ "Tab", 0xFF09 }, -{ "Linefeed", 0xFF0A }, -{ "Clear", 0xFF0B }, -{ "Return", 0xFF0D }, -{ "Pause", 0xFF13 }, -{ "Escape", 0xFF1B }, -{ "Delete", 0xFFFF }, -{ "Multi_key", 0xFF20 }, -{ "Kanji", 0xFF21 }, -{ "Home", 0xFF50 }, -{ "Left", 0xFF51 }, -{ "Up", 0xFF52 }, -{ "Right", 0xFF53 }, -{ "Down", 0xFF54 }, -{ "Prior", 0xFF55 }, -{ "Next", 0xFF56 }, -{ "End", 0xFF57 }, -{ "Begin", 0xFF58 }, -{ "Win_L", 0xFF5B }, -{ "Win_R", 0xFF5C }, -{ "App", 0xFF5D }, -{ "Select", 0xFF60 }, -{ "Print", 0xFF61 }, -{ "Execute", 0xFF62 }, -{ "Insert", 0xFF63 }, -{ "Undo", 0xFF65 }, -{ "Redo", 0xFF66 }, -{ "Menu", 0xFF67 }, -{ "Find", 0xFF68 }, -{ "Cancel", 0xFF69 }, -{ "Help", 0xFF6A }, -{ "Break", 0xFF6B }, -{ "Mode_switch", 0xFF7E }, -{ "script_switch", 0xFF7E }, -{ "Num_Lock", 0xFF7F }, -{ "KP_Space", 0xFF80 }, -{ "KP_Tab", 0xFF89 }, -{ "KP_Enter", 0xFF8D }, -{ "KP_F1", 0xFF91 }, -{ "KP_F2", 0xFF92 }, -{ "KP_F3", 0xFF93 }, -{ "KP_F4", 0xFF94 }, -{ "KP_Equal", 0xFFBD }, -{ "KP_Multiply", 0xFFAA }, -{ "KP_Add", 0xFFAB }, -{ "KP_Separator", 0xFFAC }, -{ "KP_Subtract", 0xFFAD }, -{ "KP_Decimal", 0xFFAE }, -{ "KP_Divide", 0xFFAF }, -{ "KP_0", 0xFFB0 }, -{ "KP_1", 0xFFB1 }, -{ "KP_2", 0xFFB2 }, -{ "KP_3", 0xFFB3 }, -{ "KP_4", 0xFFB4 }, -{ "KP_5", 0xFFB5 }, -{ "KP_6", 0xFFB6 }, -{ "KP_7", 0xFFB7 }, -{ "KP_8", 0xFFB8 }, -{ "KP_9", 0xFFB9 }, -{ "F1", 0xFFBE }, -{ "F2", 0xFFBF }, -{ "F3", 0xFFC0 }, -{ "F4", 0xFFC1 }, -{ "F5", 0xFFC2 }, -{ "F6", 0xFFC3 }, -{ "F7", 0xFFC4 }, -{ "F8", 0xFFC5 }, -{ "F9", 0xFFC6 }, -{ "F10", 0xFFC7 }, -{ "F11", 0xFFC8 }, -{ "L1", 0xFFC8 }, -{ "F12", 0xFFC9 }, -{ "L2", 0xFFC9 }, -{ "F13", 0xFFCA }, -{ "L3", 0xFFCA }, -{ "F14", 0xFFCB }, -{ "L4", 0xFFCB }, -{ "F15", 0xFFCC }, -{ "L5", 0xFFCC }, -{ "F16", 0xFFCD }, -{ "L6", 0xFFCD }, -{ "F17", 0xFFCE }, -{ "L7", 0xFFCE }, -{ "F18", 0xFFCF }, -{ "L8", 0xFFCF }, -{ "F19", 0xFFD0 }, -{ "L9", 0xFFD0 }, -{ "F20", 0xFFD1 }, -{ "L10", 0xFFD1 }, -{ "F21", 0xFFD2 }, -{ "R1", 0xFFD2 }, -{ "F22", 0xFFD3 }, -{ "R2", 0xFFD3 }, -{ "F23", 0xFFD4 }, -{ "R3", 0xFFD4 }, -{ "F24", 0xFFD5 }, -{ "R4", 0xFFD5 }, -{ "F25", 0xFFD6 }, -{ "R5", 0xFFD6 }, -{ "F26", 0xFFD7 }, -{ "R6", 0xFFD7 }, -{ "F27", 0xFFD8 }, -{ "R7", 0xFFD8 }, -{ "F28", 0xFFD9 }, -{ "R8", 0xFFD9 }, -{ "F29", 0xFFDA }, -{ "R9", 0xFFDA }, -{ "F30", 0xFFDB }, -{ "R10", 0xFFDB }, -{ "F31", 0xFFDC }, -{ "R11", 0xFFDC }, -{ "F32", 0xFFDD }, -{ "R12", 0xFFDD }, -{ "R13", 0xFFDE }, -{ "F33", 0xFFDE }, -{ "F34", 0xFFDF }, -{ "R14", 0xFFDF }, -{ "F35", 0xFFE0 }, -{ "R15", 0xFFE0 }, -{ "Shift_L", 0xFFE1 }, -{ "Shift_R", 0xFFE2 }, -{ "Control_L", 0xFFE3 }, -{ "Control_R", 0xFFE4 }, -{ "Caps_Lock", 0xFFE5 }, -{ "Shift_Lock", 0xFFE6 }, -{ "Meta_L", 0xFFE7 }, -{ "Meta_R", 0xFFE8 }, -{ "Alt_L", 0xFFE9 }, -{ "Alt_R", 0xFFEA }, -{ "Super_L", 0xFFEB }, -{ "Super_R", 0xFFEC }, -{ "Hyper_L", 0xFFED }, -{ "Hyper_R", 0xFFEE }, -{ "space", 0x020 }, -{ "exclam", 0x021 }, -{ "quotedbl", 0x022 }, -{ "numbersign", 0x023 }, -{ "dollar", 0x024 }, -{ "percent", 0x025 }, -{ "ampersand", 0x026 }, -{ "quoteright", 0x027 }, -{ "parenleft", 0x028 }, -{ "parenright", 0x029 }, -{ "asterisk", 0x02a }, -{ "plus", 0x02b }, -{ "comma", 0x02c }, -{ "minus", 0x02d }, -{ "period", 0x02e }, -{ "slash", 0x02f }, -{ "0", 0x030 }, -{ "1", 0x031 }, -{ "2", 0x032 }, -{ "3", 0x033 }, -{ "4", 0x034 }, -{ "5", 0x035 }, -{ "6", 0x036 }, -{ "7", 0x037 }, -{ "8", 0x038 }, -{ "9", 0x039 }, -{ "colon", 0x03a }, -{ "semicolon", 0x03b }, -{ "less", 0x03c }, -{ "equal", 0x03d }, -{ "greater", 0x03e }, -{ "question", 0x03f }, -{ "at", 0x040 }, -{ "A", 0x041 }, -{ "B", 0x042 }, -{ "C", 0x043 }, -{ "D", 0x044 }, -{ "E", 0x045 }, -{ "F", 0x046 }, -{ "G", 0x047 }, -{ "H", 0x048 }, -{ "I", 0x049 }, -{ "J", 0x04a }, -{ "K", 0x04b }, -{ "L", 0x04c }, -{ "M", 0x04d }, -{ "N", 0x04e }, -{ "O", 0x04f }, -{ "P", 0x050 }, -{ "Q", 0x051 }, -{ "R", 0x052 }, -{ "S", 0x053 }, -{ "T", 0x054 }, -{ "U", 0x055 }, -{ "V", 0x056 }, -{ "W", 0x057 }, -{ "X", 0x058 }, -{ "Y", 0x059 }, -{ "Z", 0x05a }, -{ "bracketleft", 0x05b }, -{ "backslash", 0x05c }, -{ "bracketright", 0x05d }, -{ "asciicircum", 0x05e }, -{ "underscore", 0x05f }, -{ "quoteleft", 0x060 }, -{ "a", 0x061 }, -{ "b", 0x062 }, -{ "c", 0x063 }, -{ "d", 0x064 }, -{ "e", 0x065 }, -{ "f", 0x066 }, -{ "g", 0x067 }, -{ "h", 0x068 }, -{ "i", 0x069 }, -{ "j", 0x06a }, -{ "k", 0x06b }, -{ "l", 0x06c }, -{ "m", 0x06d }, -{ "n", 0x06e }, -{ "o", 0x06f }, -{ "p", 0x070 }, -{ "q", 0x071 }, -{ "r", 0x072 }, -{ "s", 0x073 }, -{ "t", 0x074 }, -{ "u", 0x075 }, -{ "v", 0x076 }, -{ "w", 0x077 }, -{ "x", 0x078 }, -{ "y", 0x079 }, -{ "z", 0x07a }, -{ "braceleft", 0x07b }, -{ "bar", 0x07c }, -{ "braceright", 0x07d }, -{ "asciitilde", 0x07e }, -{ "nobreakspace", 0x0a0 }, -{ "exclamdown", 0x0a1 }, -{ "cent", 0x0a2 }, -{ "sterling", 0x0a3 }, -{ "currency", 0x0a4 }, -{ "yen", 0x0a5 }, -{ "brokenbar", 0x0a6 }, -{ "section", 0x0a7 }, -{ "diaeresis", 0x0a8 }, -{ "copyright", 0x0a9 }, -{ "ordfeminine", 0x0aa }, -{ "guillemotleft", 0x0ab }, -{ "notsign", 0x0ac }, -{ "hyphen", 0x0ad }, -{ "registered", 0x0ae }, -{ "macron", 0x0af }, -{ "degree", 0x0b0 }, -{ "plusminus", 0x0b1 }, -{ "twosuperior", 0x0b2 }, -{ "threesuperior", 0x0b3 }, -{ "acute", 0x0b4 }, -{ "mu", 0x0b5 }, -{ "paragraph", 0x0b6 }, -{ "periodcentered", 0x0b7 }, -{ "cedilla", 0x0b8 }, -{ "onesuperior", 0x0b9 }, -{ "masculine", 0x0ba }, -{ "guillemotright", 0x0bb }, -{ "onequarter", 0x0bc }, -{ "onehalf", 0x0bd }, -{ "threequarters", 0x0be }, -{ "questiondown", 0x0bf }, -{ "Agrave", 0x0c0 }, -{ "Aacute", 0x0c1 }, -{ "Acircumflex", 0x0c2 }, -{ "Atilde", 0x0c3 }, -{ "Adiaeresis", 0x0c4 }, -{ "Aring", 0x0c5 }, -{ "AE", 0x0c6 }, -{ "Ccedilla", 0x0c7 }, -{ "Egrave", 0x0c8 }, -{ "Eacute", 0x0c9 }, -{ "Ecircumflex", 0x0ca }, -{ "Ediaeresis", 0x0cb }, -{ "Igrave", 0x0cc }, -{ "Iacute", 0x0cd }, -{ "Icircumflex", 0x0ce }, -{ "Idiaeresis", 0x0cf }, -{ "Eth", 0x0d0 }, -{ "Ntilde", 0x0d1 }, -{ "Ograve", 0x0d2 }, -{ "Oacute", 0x0d3 }, -{ "Ocircumflex", 0x0d4 }, -{ "Otilde", 0x0d5 }, -{ "Odiaeresis", 0x0d6 }, -{ "multiply", 0x0d7 }, -{ "Ooblique", 0x0d8 }, -{ "Ugrave", 0x0d9 }, -{ "Uacute", 0x0da }, -{ "Ucircumflex", 0x0db }, -{ "Udiaeresis", 0x0dc }, -{ "Yacute", 0x0dd }, -{ "Thorn", 0x0de }, -{ "ssharp", 0x0df }, -{ "agrave", 0x0e0 }, -{ "aacute", 0x0e1 }, -{ "acircumflex", 0x0e2 }, -{ "atilde", 0x0e3 }, -{ "adiaeresis", 0x0e4 }, -{ "aring", 0x0e5 }, -{ "ae", 0x0e6 }, -{ "ccedilla", 0x0e7 }, -{ "egrave", 0x0e8 }, -{ "eacute", 0x0e9 }, -{ "ecircumflex", 0x0ea }, -{ "ediaeresis", 0x0eb }, -{ "igrave", 0x0ec }, -{ "iacute", 0x0ed }, -{ "icircumflex", 0x0ee }, -{ "idiaeresis", 0x0ef }, -{ "eth", 0x0f0 }, -{ "ntilde", 0x0f1 }, -{ "ograve", 0x0f2 }, -{ "oacute", 0x0f3 }, -{ "ocircumflex", 0x0f4 }, -{ "otilde", 0x0f5 }, -{ "odiaeresis", 0x0f6 }, -{ "division", 0x0f7 }, -{ "oslash", 0x0f8 }, -{ "ugrave", 0x0f9 }, -{ "uacute", 0x0fa }, -{ "ucircumflex", 0x0fb }, -{ "udiaeresis", 0x0fc }, -{ "yacute", 0x0fd }, -{ "thorn", 0x0fe }, -{ "ydiaeresis", 0x0ff }, -{ "Aogonek", 0x1a1 }, -{ "breve", 0x1a2 }, -{ "Lstroke", 0x1a3 }, -{ "Lcaron", 0x1a5 }, -{ "Sacute", 0x1a6 }, -{ "Scaron", 0x1a9 }, -{ "Scedilla", 0x1aa }, -{ "Tcaron", 0x1ab }, -{ "Zacute", 0x1ac }, -{ "Zcaron", 0x1ae }, -{ "Zabovedot", 0x1af }, -{ "aogonek", 0x1b1 }, -{ "ogonek", 0x1b2 }, -{ "lstroke", 0x1b3 }, -{ "lcaron", 0x1b5 }, -{ "sacute", 0x1b6 }, -{ "caron", 0x1b7 }, -{ "scaron", 0x1b9 }, -{ "scedilla", 0x1ba }, -{ "tcaron", 0x1bb }, -{ "zacute", 0x1bc }, -{ "doubleacute", 0x1bd }, -{ "zcaron", 0x1be }, -{ "zabovedot", 0x1bf }, -{ "Racute", 0x1c0 }, -{ "Abreve", 0x1c3 }, -{ "Cacute", 0x1c6 }, -{ "Ccaron", 0x1c8 }, -{ "Eogonek", 0x1ca }, -{ "Ecaron", 0x1cc }, -{ "Dcaron", 0x1cf }, -{ "Nacute", 0x1d1 }, -{ "Ncaron", 0x1d2 }, -{ "Odoubleacute", 0x1d5 }, -{ "Rcaron", 0x1d8 }, -{ "Uring", 0x1d9 }, -{ "Udoubleacute", 0x1db }, -{ "Tcedilla", 0x1de }, -{ "racute", 0x1e0 }, -{ "abreve", 0x1e3 }, -{ "cacute", 0x1e6 }, -{ "ccaron", 0x1e8 }, -{ "eogonek", 0x1ea }, -{ "ecaron", 0x1ec }, -{ "dcaron", 0x1ef }, -{ "nacute", 0x1f1 }, -{ "ncaron", 0x1f2 }, -{ "odoubleacute", 0x1f5 }, -{ "udoubleacute", 0x1fb }, -{ "rcaron", 0x1f8 }, -{ "uring", 0x1f9 }, -{ "tcedilla", 0x1fe }, -{ "abovedot", 0x1ff }, -{ "Hstroke", 0x2a1 }, -{ "Hcircumflex", 0x2a6 }, -{ "Iabovedot", 0x2a9 }, -{ "Gbreve", 0x2ab }, -{ "Jcircumflex", 0x2ac }, -{ "hstroke", 0x2b1 }, -{ "hcircumflex", 0x2b6 }, -{ "idotless", 0x2b9 }, -{ "gbreve", 0x2bb }, -{ "jcircumflex", 0x2bc }, -{ "Cabovedot", 0x2c5 }, -{ "Ccircumflex", 0x2c6 }, -{ "Gabovedot", 0x2d5 }, -{ "Gcircumflex", 0x2d8 }, -{ "Ubreve", 0x2dd }, -{ "Scircumflex", 0x2de }, -{ "cabovedot", 0x2e5 }, -{ "ccircumflex", 0x2e6 }, -{ "gabovedot", 0x2f5 }, -{ "gcircumflex", 0x2f8 }, -{ "ubreve", 0x2fd }, -{ "scircumflex", 0x2fe }, -{ "kappa", 0x3a2 }, -{ "Rcedilla", 0x3a3 }, -{ "Itilde", 0x3a5 }, -{ "Lcedilla", 0x3a6 }, -{ "Emacron", 0x3aa }, -{ "Gcedilla", 0x3ab }, -{ "Tslash", 0x3ac }, -{ "rcedilla", 0x3b3 }, -{ "itilde", 0x3b5 }, -{ "lcedilla", 0x3b6 }, -{ "emacron", 0x3ba }, -{ "gacute", 0x3bb }, -{ "tslash", 0x3bc }, -{ "ENG", 0x3bd }, -{ "eng", 0x3bf }, -{ "Amacron", 0x3c0 }, -{ "Iogonek", 0x3c7 }, -{ "Eabovedot", 0x3cc }, -{ "Imacron", 0x3cf }, -{ "Ncedilla", 0x3d1 }, -{ "Omacron", 0x3d2 }, -{ "Kcedilla", 0x3d3 }, -{ "Uogonek", 0x3d9 }, -{ "Utilde", 0x3dd }, -{ "Umacron", 0x3de }, -{ "amacron", 0x3e0 }, -{ "iogonek", 0x3e7 }, -{ "eabovedot", 0x3ec }, -{ "imacron", 0x3ef }, -{ "ncedilla", 0x3f1 }, -{ "omacron", 0x3f2 }, -{ "kcedilla", 0x3f3 }, -{ "uogonek", 0x3f9 }, -{ "utilde", 0x3fd }, -{ "umacron", 0x3fe }, -{ "overline", 0x47e }, -{ "kana_fullstop", 0x4a1 }, -{ "kana_openingbracket", 0x4a2 }, -{ "kana_closingbracket", 0x4a3 }, -{ "kana_comma", 0x4a4 }, -{ "kana_middledot", 0x4a5 }, -{ "kana_WO", 0x4a6 }, -{ "kana_a", 0x4a7 }, -{ "kana_i", 0x4a8 }, -{ "kana_u", 0x4a9 }, -{ "kana_e", 0x4aa }, -{ "kana_o", 0x4ab }, -{ "kana_ya", 0x4ac }, -{ "kana_yu", 0x4ad }, -{ "kana_yo", 0x4ae }, -{ "kana_tu", 0x4af }, -{ "prolongedsound", 0x4b0 }, -{ "kana_A", 0x4b1 }, -{ "kana_I", 0x4b2 }, -{ "kana_U", 0x4b3 }, -{ "kana_E", 0x4b4 }, -{ "kana_O", 0x4b5 }, -{ "kana_KA", 0x4b6 }, -{ "kana_KI", 0x4b7 }, -{ "kana_KU", 0x4b8 }, -{ "kana_KE", 0x4b9 }, -{ "kana_KO", 0x4ba }, -{ "kana_SA", 0x4bb }, -{ "kana_SHI", 0x4bc }, -{ "kana_SU", 0x4bd }, -{ "kana_SE", 0x4be }, -{ "kana_SO", 0x4bf }, -{ "kana_TA", 0x4c0 }, -{ "kana_TI", 0x4c1 }, -{ "kana_TU", 0x4c2 }, -{ "kana_TE", 0x4c3 }, -{ "kana_TO", 0x4c4 }, -{ "kana_NA", 0x4c5 }, -{ "kana_NI", 0x4c6 }, -{ "kana_NU", 0x4c7 }, -{ "kana_NE", 0x4c8 }, -{ "kana_NO", 0x4c9 }, -{ "kana_HA", 0x4ca }, -{ "kana_HI", 0x4cb }, -{ "kana_HU", 0x4cc }, -{ "kana_HE", 0x4cd }, -{ "kana_HO", 0x4ce }, -{ "kana_MA", 0x4cf }, -{ "kana_MI", 0x4d0 }, -{ "kana_MU", 0x4d1 }, -{ "kana_ME", 0x4d2 }, -{ "kana_MO", 0x4d3 }, -{ "kana_YA", 0x4d4 }, -{ "kana_YU", 0x4d5 }, -{ "kana_YO", 0x4d6 }, -{ "kana_RA", 0x4d7 }, -{ "kana_RI", 0x4d8 }, -{ "kana_RU", 0x4d9 }, -{ "kana_RE", 0x4da }, -{ "kana_RO", 0x4db }, -{ "kana_WA", 0x4dc }, -{ "kana_N", 0x4dd }, -{ "voicedsound", 0x4de }, -{ "semivoicedsound", 0x4df }, -{ "kana_switch", 0xFF7E }, -{ "Arabic_comma", 0x5ac }, -{ "Arabic_semicolon", 0x5bb }, -{ "Arabic_question_mark", 0x5bf }, -{ "Arabic_hamza", 0x5c1 }, -{ "Arabic_maddaonalef", 0x5c2 }, -{ "Arabic_hamzaonalef", 0x5c3 }, -{ "Arabic_hamzaonwaw", 0x5c4 }, -{ "Arabic_hamzaunderalef", 0x5c5 }, -{ "Arabic_hamzaonyeh", 0x5c6 }, -{ "Arabic_alef", 0x5c7 }, -{ "Arabic_beh", 0x5c8 }, -{ "Arabic_tehmarbuta", 0x5c9 }, -{ "Arabic_teh", 0x5ca }, -{ "Arabic_theh", 0x5cb }, -{ "Arabic_jeem", 0x5cc }, -{ "Arabic_hah", 0x5cd }, -{ "Arabic_khah", 0x5ce }, -{ "Arabic_dal", 0x5cf }, -{ "Arabic_thal", 0x5d0 }, -{ "Arabic_ra", 0x5d1 }, -{ "Arabic_zain", 0x5d2 }, -{ "Arabic_seen", 0x5d3 }, -{ "Arabic_sheen", 0x5d4 }, -{ "Arabic_sad", 0x5d5 }, -{ "Arabic_dad", 0x5d6 }, -{ "Arabic_tah", 0x5d7 }, -{ "Arabic_zah", 0x5d8 }, -{ "Arabic_ain", 0x5d9 }, -{ "Arabic_ghain", 0x5da }, -{ "Arabic_tatweel", 0x5e0 }, -{ "Arabic_feh", 0x5e1 }, -{ "Arabic_qaf", 0x5e2 }, -{ "Arabic_kaf", 0x5e3 }, -{ "Arabic_lam", 0x5e4 }, -{ "Arabic_meem", 0x5e5 }, -{ "Arabic_noon", 0x5e6 }, -{ "Arabic_heh", 0x5e7 }, -{ "Arabic_waw", 0x5e8 }, -{ "Arabic_alefmaksura", 0x5e9 }, -{ "Arabic_yeh", 0x5ea }, -{ "Arabic_fathatan", 0x5eb }, -{ "Arabic_dammatan", 0x5ec }, -{ "Arabic_kasratan", 0x5ed }, -{ "Arabic_fatha", 0x5ee }, -{ "Arabic_damma", 0x5ef }, -{ "Arabic_kasra", 0x5f0 }, -{ "Arabic_shadda", 0x5f1 }, -{ "Arabic_sukun", 0x5f2 }, -{ "Arabic_switch", 0xFF7E }, -{ "Serbian_dje", 0x6a1 }, -{ "Macedonia_gje", 0x6a2 }, -{ "Cyrillic_io", 0x6a3 }, -{ "Ukranian_je", 0x6a4 }, -{ "Macedonia_dse", 0x6a5 }, -{ "Ukranian_i", 0x6a6 }, -{ "Ukranian_yi", 0x6a7 }, -{ "Serbian_je", 0x6a8 }, -{ "Serbian_lje", 0x6a9 }, -{ "Serbian_nje", 0x6aa }, -{ "Serbian_tshe", 0x6ab }, -{ "Macedonia_kje", 0x6ac }, -{ "Byelorussian_shortu", 0x6ae }, -{ "Serbian_dze", 0x6af }, -{ "numerosign", 0x6b0 }, -{ "Serbian_DJE", 0x6b1 }, -{ "Macedonia_GJE", 0x6b2 }, -{ "Cyrillic_IO", 0x6b3 }, -{ "Ukranian_JE", 0x6b4 }, -{ "Macedonia_DSE", 0x6b5 }, -{ "Ukranian_I", 0x6b6 }, -{ "Ukranian_YI", 0x6b7 }, -{ "Serbian_JE", 0x6b8 }, -{ "Serbian_LJE", 0x6b9 }, -{ "Serbian_NJE", 0x6ba }, -{ "Serbian_TSHE", 0x6bb }, -{ "Macedonia_KJE", 0x6bc }, -{ "Byelorussian_SHORTU", 0x6be }, -{ "Serbian_DZE", 0x6bf }, -{ "Cyrillic_yu", 0x6c0 }, -{ "Cyrillic_a", 0x6c1 }, -{ "Cyrillic_be", 0x6c2 }, -{ "Cyrillic_tse", 0x6c3 }, -{ "Cyrillic_de", 0x6c4 }, -{ "Cyrillic_ie", 0x6c5 }, -{ "Cyrillic_ef", 0x6c6 }, -{ "Cyrillic_ghe", 0x6c7 }, -{ "Cyrillic_ha", 0x6c8 }, -{ "Cyrillic_i", 0x6c9 }, -{ "Cyrillic_shorti", 0x6ca }, -{ "Cyrillic_ka", 0x6cb }, -{ "Cyrillic_el", 0x6cc }, -{ "Cyrillic_em", 0x6cd }, -{ "Cyrillic_en", 0x6ce }, -{ "Cyrillic_o", 0x6cf }, -{ "Cyrillic_pe", 0x6d0 }, -{ "Cyrillic_ya", 0x6d1 }, -{ "Cyrillic_er", 0x6d2 }, -{ "Cyrillic_es", 0x6d3 }, -{ "Cyrillic_te", 0x6d4 }, -{ "Cyrillic_u", 0x6d5 }, -{ "Cyrillic_zhe", 0x6d6 }, -{ "Cyrillic_ve", 0x6d7 }, -{ "Cyrillic_softsign", 0x6d8 }, -{ "Cyrillic_yeru", 0x6d9 }, -{ "Cyrillic_ze", 0x6da }, -{ "Cyrillic_sha", 0x6db }, -{ "Cyrillic_e", 0x6dc }, -{ "Cyrillic_shcha", 0x6dd }, -{ "Cyrillic_che", 0x6de }, -{ "Cyrillic_hardsign", 0x6df }, -{ "Cyrillic_YU", 0x6e0 }, -{ "Cyrillic_A", 0x6e1 }, -{ "Cyrillic_BE", 0x6e2 }, -{ "Cyrillic_TSE", 0x6e3 }, -{ "Cyrillic_DE", 0x6e4 }, -{ "Cyrillic_IE", 0x6e5 }, -{ "Cyrillic_EF", 0x6e6 }, -{ "Cyrillic_GHE", 0x6e7 }, -{ "Cyrillic_HA", 0x6e8 }, -{ "Cyrillic_I", 0x6e9 }, -{ "Cyrillic_SHORTI", 0x6ea }, -{ "Cyrillic_KA", 0x6eb }, -{ "Cyrillic_EL", 0x6ec }, -{ "Cyrillic_EM", 0x6ed }, -{ "Cyrillic_EN", 0x6ee }, -{ "Cyrillic_O", 0x6ef }, -{ "Cyrillic_PE", 0x6f0 }, -{ "Cyrillic_YA", 0x6f1 }, -{ "Cyrillic_ER", 0x6f2 }, -{ "Cyrillic_ES", 0x6f3 }, -{ "Cyrillic_TE", 0x6f4 }, -{ "Cyrillic_U", 0x6f5 }, -{ "Cyrillic_ZHE", 0x6f6 }, -{ "Cyrillic_VE", 0x6f7 }, -{ "Cyrillic_SOFTSIGN", 0x6f8 }, -{ "Cyrillic_YERU", 0x6f9 }, -{ "Cyrillic_ZE", 0x6fa }, -{ "Cyrillic_SHA", 0x6fb }, -{ "Cyrillic_E", 0x6fc }, -{ "Cyrillic_SHCHA", 0x6fd }, -{ "Cyrillic_CHE", 0x6fe }, -{ "Cyrillic_HARDSIGN", 0x6ff }, -{ "Greek_ALPHAaccent", 0x7a1 }, -{ "Greek_EPSILONaccent", 0x7a2 }, -{ "Greek_ETAaccent", 0x7a3 }, -{ "Greek_IOTAaccent", 0x7a4 }, -{ "Greek_IOTAdiaeresis", 0x7a5 }, -{ "Greek_IOTAaccentdiaeresis", 0x7a6 }, -{ "Greek_OMICRONaccent", 0x7a7 }, -{ "Greek_UPSILONaccent", 0x7a8 }, -{ "Greek_UPSILONdieresis", 0x7a9 }, -{ "Greek_UPSILONaccentdieresis", 0x7aa }, -{ "Greek_OMEGAaccent", 0x7ab }, -{ "Greek_alphaaccent", 0x7b1 }, -{ "Greek_epsilonaccent", 0x7b2 }, -{ "Greek_etaaccent", 0x7b3 }, -{ "Greek_iotaaccent", 0x7b4 }, -{ "Greek_iotadieresis", 0x7b5 }, -{ "Greek_iotaaccentdieresis", 0x7b6 }, -{ "Greek_omicronaccent", 0x7b7 }, -{ "Greek_upsilonaccent", 0x7b8 }, -{ "Greek_upsilondieresis", 0x7b9 }, -{ "Greek_upsilonaccentdieresis", 0x7ba }, -{ "Greek_omegaaccent", 0x7bb }, -{ "Greek_ALPHA", 0x7c1 }, -{ "Greek_BETA", 0x7c2 }, -{ "Greek_GAMMA", 0x7c3 }, -{ "Greek_DELTA", 0x7c4 }, -{ "Greek_EPSILON", 0x7c5 }, -{ "Greek_ZETA", 0x7c6 }, -{ "Greek_ETA", 0x7c7 }, -{ "Greek_THETA", 0x7c8 }, -{ "Greek_IOTA", 0x7c9 }, -{ "Greek_KAPPA", 0x7ca }, -{ "Greek_LAMBDA", 0x7cb }, -{ "Greek_MU", 0x7cc }, -{ "Greek_NU", 0x7cd }, -{ "Greek_XI", 0x7ce }, -{ "Greek_OMICRON", 0x7cf }, -{ "Greek_PI", 0x7d0 }, -{ "Greek_RHO", 0x7d1 }, -{ "Greek_SIGMA", 0x7d2 }, -{ "Greek_TAU", 0x7d4 }, -{ "Greek_UPSILON", 0x7d5 }, -{ "Greek_PHI", 0x7d6 }, -{ "Greek_CHI", 0x7d7 }, -{ "Greek_PSI", 0x7d8 }, -{ "Greek_OMEGA", 0x7d9 }, -{ "Greek_alpha", 0x7e1 }, -{ "Greek_beta", 0x7e2 }, -{ "Greek_gamma", 0x7e3 }, -{ "Greek_delta", 0x7e4 }, -{ "Greek_epsilon", 0x7e5 }, -{ "Greek_zeta", 0x7e6 }, -{ "Greek_eta", 0x7e7 }, -{ "Greek_theta", 0x7e8 }, -{ "Greek_iota", 0x7e9 }, -{ "Greek_kappa", 0x7ea }, -{ "Greek_lambda", 0x7eb }, -{ "Greek_mu", 0x7ec }, -{ "Greek_nu", 0x7ed }, -{ "Greek_xi", 0x7ee }, -{ "Greek_omicron", 0x7ef }, -{ "Greek_pi", 0x7f0 }, -{ "Greek_rho", 0x7f1 }, -{ "Greek_sigma", 0x7f2 }, -{ "Greek_finalsmallsigma", 0x7f3 }, -{ "Greek_tau", 0x7f4 }, -{ "Greek_upsilon", 0x7f5 }, -{ "Greek_phi", 0x7f6 }, -{ "Greek_chi", 0x7f7 }, -{ "Greek_psi", 0x7f8 }, -{ "Greek_omega", 0x7f9 }, -{ "Greek_switch", 0xFF7E }, -{ "leftradical", 0x8a1 }, -{ "topleftradical", 0x8a2 }, -{ "horizconnector", 0x8a3 }, -{ "topintegral", 0x8a4 }, -{ "botintegral", 0x8a5 }, -{ "vertconnector", 0x8a6 }, -{ "topleftsqbracket", 0x8a7 }, -{ "botleftsqbracket", 0x8a8 }, -{ "toprightsqbracket", 0x8a9 }, -{ "botrightsqbracket", 0x8aa }, -{ "topleftparens", 0x8ab }, -{ "botleftparens", 0x8ac }, -{ "toprightparens", 0x8ad }, -{ "botrightparens", 0x8ae }, -{ "leftmiddlecurlybrace", 0x8af }, -{ "rightmiddlecurlybrace", 0x8b0 }, -{ "topleftsummation", 0x8b1 }, -{ "botleftsummation", 0x8b2 }, -{ "topvertsummationconnector", 0x8b3 }, -{ "botvertsummationconnector", 0x8b4 }, -{ "toprightsummation", 0x8b5 }, -{ "botrightsummation", 0x8b6 }, -{ "rightmiddlesummation", 0x8b7 }, -{ "lessthanequal", 0x8bc }, -{ "notequal", 0x8bd }, -{ "greaterthanequal", 0x8be }, -{ "integral", 0x8bf }, -{ "therefore", 0x8c0 }, -{ "variation", 0x8c1 }, -{ "infinity", 0x8c2 }, -{ "nabla", 0x8c5 }, -{ "approximate", 0x8c8 }, -{ "similarequal", 0x8c9 }, -{ "ifonlyif", 0x8cd }, -{ "implies", 0x8ce }, -{ "identical", 0x8cf }, -{ "radical", 0x8d6 }, -{ "includedin", 0x8da }, -{ "includes", 0x8db }, -{ "intersection", 0x8dc }, -{ "union", 0x8dd }, -{ "logicaland", 0x8de }, -{ "logicalor", 0x8df }, -{ "partialderivative", 0x8ef }, -{ "function", 0x8f6 }, -{ "leftarrow", 0x8fb }, -{ "uparrow", 0x8fc }, -{ "rightarrow", 0x8fd }, -{ "downarrow", 0x8fe }, -{ "blank", 0x9df }, -{ "soliddiamond", 0x9e0 }, -{ "checkerboard", 0x9e1 }, -{ "ht", 0x9e2 }, -{ "ff", 0x9e3 }, -{ "cr", 0x9e4 }, -{ "lf", 0x9e5 }, -{ "nl", 0x9e8 }, -{ "vt", 0x9e9 }, -{ "lowrightcorner", 0x9ea }, -{ "uprightcorner", 0x9eb }, -{ "upleftcorner", 0x9ec }, -{ "lowleftcorner", 0x9ed }, -{ "crossinglines", 0x9ee }, -{ "horizlinescan1", 0x9ef }, -{ "horizlinescan3", 0x9f0 }, -{ "horizlinescan5", 0x9f1 }, -{ "horizlinescan7", 0x9f2 }, -{ "horizlinescan9", 0x9f3 }, -{ "leftt", 0x9f4 }, -{ "rightt", 0x9f5 }, -{ "bott", 0x9f6 }, -{ "topt", 0x9f7 }, -{ "vertbar", 0x9f8 }, -{ "emspace", 0xaa1 }, -{ "enspace", 0xaa2 }, -{ "em3space", 0xaa3 }, -{ "em4space", 0xaa4 }, -{ "digitspace", 0xaa5 }, -{ "punctspace", 0xaa6 }, -{ "thinspace", 0xaa7 }, -{ "hairspace", 0xaa8 }, -{ "emdash", 0xaa9 }, -{ "endash", 0xaaa }, -{ "signifblank", 0xaac }, -{ "ellipsis", 0xaae }, -{ "doubbaselinedot", 0xaaf }, -{ "onethird", 0xab0 }, -{ "twothirds", 0xab1 }, -{ "onefifth", 0xab2 }, -{ "twofifths", 0xab3 }, -{ "threefifths", 0xab4 }, -{ "fourfifths", 0xab5 }, -{ "onesixth", 0xab6 }, -{ "fivesixths", 0xab7 }, -{ "careof", 0xab8 }, -{ "figdash", 0xabb }, -{ "leftanglebracket", 0xabc }, -{ "decimalpoint", 0xabd }, -{ "rightanglebracket", 0xabe }, -{ "marker", 0xabf }, -{ "oneeighth", 0xac3 }, -{ "threeeighths", 0xac4 }, -{ "fiveeighths", 0xac5 }, -{ "seveneighths", 0xac6 }, -{ "trademark", 0xac9 }, -{ "signaturemark", 0xaca }, -{ "trademarkincircle", 0xacb }, -{ "leftopentriangle", 0xacc }, -{ "rightopentriangle", 0xacd }, -{ "emopencircle", 0xace }, -{ "emopenrectangle", 0xacf }, -{ "leftsinglequotemark", 0xad0 }, -{ "rightsinglequotemark", 0xad1 }, -{ "leftdoublequotemark", 0xad2 }, -{ "rightdoublequotemark", 0xad3 }, -{ "prescription", 0xad4 }, -{ "minutes", 0xad6 }, -{ "seconds", 0xad7 }, -{ "latincross", 0xad9 }, -{ "hexagram", 0xada }, -{ "filledrectbullet", 0xadb }, -{ "filledlefttribullet", 0xadc }, -{ "filledrighttribullet", 0xadd }, -{ "emfilledcircle", 0xade }, -{ "emfilledrect", 0xadf }, -{ "enopencircbullet", 0xae0 }, -{ "enopensquarebullet", 0xae1 }, -{ "openrectbullet", 0xae2 }, -{ "opentribulletup", 0xae3 }, -{ "opentribulletdown", 0xae4 }, -{ "openstar", 0xae5 }, -{ "enfilledcircbullet", 0xae6 }, -{ "enfilledsqbullet", 0xae7 }, -{ "filledtribulletup", 0xae8 }, -{ "filledtribulletdown", 0xae9 }, -{ "leftpointer", 0xaea }, -{ "rightpointer", 0xaeb }, -{ "club", 0xaec }, -{ "diamond", 0xaed }, -{ "heart", 0xaee }, -{ "maltesecross", 0xaf0 }, -{ "dagger", 0xaf1 }, -{ "doubledagger", 0xaf2 }, -{ "checkmark", 0xaf3 }, -{ "ballotcross", 0xaf4 }, -{ "musicalsharp", 0xaf5 }, -{ "musicalflat", 0xaf6 }, -{ "malesymbol", 0xaf7 }, -{ "femalesymbol", 0xaf8 }, -{ "telephone", 0xaf9 }, -{ "telephonerecorder", 0xafa }, -{ "phonographcopyright", 0xafb }, -{ "caret", 0xafc }, -{ "singlelowquotemark", 0xafd }, -{ "doublelowquotemark", 0xafe }, -{ "cursor", 0xaff }, -{ "leftcaret", 0xba3 }, -{ "rightcaret", 0xba6 }, -{ "downcaret", 0xba8 }, -{ "upcaret", 0xba9 }, -{ "overbar", 0xbc0 }, -{ "downtack", 0xbc2 }, -{ "upshoe", 0xbc3 }, -{ "downstile", 0xbc4 }, -{ "underbar", 0xbc6 }, -{ "jot", 0xbca }, -{ "quad", 0xbcc }, -{ "uptack", 0xbce }, -{ "circle", 0xbcf }, -{ "upstile", 0xbd3 }, -{ "downshoe", 0xbd6 }, -{ "rightshoe", 0xbd8 }, -{ "leftshoe", 0xbda }, -{ "lefttack", 0xbdc }, -{ "righttack", 0xbfc }, -{ "hebrew_aleph", 0xce0 }, -{ "hebrew_beth", 0xce1 }, -{ "hebrew_gimmel", 0xce2 }, -{ "hebrew_daleth", 0xce3 }, -{ "hebrew_he", 0xce4 }, -{ "hebrew_waw", 0xce5 }, -{ "hebrew_zayin", 0xce6 }, -{ "hebrew_het", 0xce7 }, -{ "hebrew_teth", 0xce8 }, -{ "hebrew_yod", 0xce9 }, -{ "hebrew_finalkaph", 0xcea }, -{ "hebrew_kaph", 0xceb }, -{ "hebrew_lamed", 0xcec }, -{ "hebrew_finalmem", 0xced }, -{ "hebrew_mem", 0xcee }, -{ "hebrew_finalnun", 0xcef }, -{ "hebrew_nun", 0xcf0 }, -{ "hebrew_samekh", 0xcf1 }, -{ "hebrew_ayin", 0xcf2 }, -{ "hebrew_finalpe", 0xcf3 }, -{ "hebrew_pe", 0xcf4 }, -{ "hebrew_finalzadi", 0xcf5 }, -{ "hebrew_zadi", 0xcf6 }, -{ "hebrew_kuf", 0xcf7 }, -{ "hebrew_resh", 0xcf8 }, -{ "hebrew_shin", 0xcf9 }, -{ "hebrew_taf", 0xcfa }, -{ "Hebrew_switch", 0xFF7E }, diff --git a/generic/tk.h b/generic/tk.h deleted file mode 100644 index 6fcff0b..0000000 --- a/generic/tk.h +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * tk.h -- - * - * Declarations for Tk-related things that are visible - * outside of the Tk module itself. - * - * Copyright (c) 1989-1994 The Regents of the University of California. - * Copyright (c) 1994 The Australian National University. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tk.h,v 1.12 1998/09/14 18:23:02 stanton Exp $ - */ - -#ifndef _TK -#define _TK - -/* - * When version numbers change here, you must also go into the following files - * and update the version numbers: - * - * README - * unix/configure.in - * win/makefile.bc (Not for patch release updates) - * win/makefile.vc (Not for patch release updates) - * library/tk.tcl - * - * The release level should be 0 for alpha, 1 for beta, and 2 for - * final/patch. The release serial value is the number that follows the - * "a", "b", or "p" in the patch level; for example, if the patch level - * is 4.3b2, TK_RELEASE_SERIAL is 2. It restarts at 1 whenever the - * release level is changed, except for the final release, which should - * be 0. - * - * You may also need to update some of these files when the numbers change - * for the version of Tcl that this release of Tk is compiled against. - */ - -#define TK_MAJOR_VERSION 8 -#define TK_MINOR_VERSION 0 -#define TK_RELEASE_LEVEL 2 -#define TK_RELEASE_SERIAL 3 - -#define TK_VERSION "8.0" -#define TK_PATCH_LEVEL "8.0.3" - -/* - * A special definition used to allow this header file to be included - * in resource files. - */ - -#ifndef RESOURCE_INCLUDED - -/* - * The following definitions set up the proper options for Macintosh - * compilers. We use this method because there is no autoconf equivalent. - */ - -#ifdef MAC_TCL -# ifndef REDO_KEYSYM_LOOKUP -# define REDO_KEYSYM_LOOKUP -# endif -#endif - -#ifndef _TCL -# include <tcl.h> -#endif -#ifndef _XLIB_H -# ifdef MAC_TCL -# include <Xlib.h> -# include <X.h> -# else -# include <X11/Xlib.h> -# endif -#endif -#ifdef __STDC__ -# include <stddef.h> -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * Decide whether or not to use input methods. - */ - -#ifdef XNQueryInputStyle -#define TK_USE_INPUT_METHODS -#endif - -/* - * Dummy types that are used by clients: - */ - -typedef struct Tk_BindingTable_ *Tk_BindingTable; -typedef struct Tk_Canvas_ *Tk_Canvas; -typedef struct Tk_Cursor_ *Tk_Cursor; -typedef struct Tk_ErrorHandler_ *Tk_ErrorHandler; -typedef struct Tk_Font_ *Tk_Font; -typedef struct Tk_Image__ *Tk_Image; -typedef struct Tk_ImageMaster_ *Tk_ImageMaster; -typedef struct Tk_TextLayout_ *Tk_TextLayout; -typedef struct Tk_Window_ *Tk_Window; -typedef struct Tk_3DBorder_ *Tk_3DBorder; - -/* - * Additional types exported to clients. - */ - -typedef char *Tk_Uid; - -/* - * Structure used to specify how to handle argv options. - */ - -typedef struct { - char *key; /* The key string that flags the option in the - * argv array. */ - int type; /* Indicates option type; see below. */ - char *src; /* Value to be used in setting dst; usage - * depends on type. */ - char *dst; /* Address of value to be modified; usage - * depends on type. */ - char *help; /* Documentation message describing this option. */ -} Tk_ArgvInfo; - -/* - * Legal values for the type field of a Tk_ArgvInfo: see the user - * documentation for details. - */ - -#define TK_ARGV_CONSTANT 15 -#define TK_ARGV_INT 16 -#define TK_ARGV_STRING 17 -#define TK_ARGV_UID 18 -#define TK_ARGV_REST 19 -#define TK_ARGV_FLOAT 20 -#define TK_ARGV_FUNC 21 -#define TK_ARGV_GENFUNC 22 -#define TK_ARGV_HELP 23 -#define TK_ARGV_CONST_OPTION 24 -#define TK_ARGV_OPTION_VALUE 25 -#define TK_ARGV_OPTION_NAME_VALUE 26 -#define TK_ARGV_END 27 - -/* - * Flag bits for passing to Tk_ParseArgv: - */ - -#define TK_ARGV_NO_DEFAULTS 0x1 -#define TK_ARGV_NO_LEFTOVERS 0x2 -#define TK_ARGV_NO_ABBREV 0x4 -#define TK_ARGV_DONT_SKIP_FIRST_ARG 0x8 - -/* - * Structure used to describe application-specific configuration - * options: indicates procedures to call to parse an option and - * to return a text string describing an option. - */ - -typedef int (Tk_OptionParseProc) _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, char *widgRec, - int offset)); -typedef char *(Tk_OptionPrintProc) _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin, char *widgRec, int offset, - Tcl_FreeProc **freeProcPtr)); - -typedef struct Tk_CustomOption { - Tk_OptionParseProc *parseProc; /* Procedure to call to parse an - * option and store it in converted - * form. */ - Tk_OptionPrintProc *printProc; /* Procedure to return a printable - * string describing an existing - * option. */ - ClientData clientData; /* Arbitrary one-word value used by - * option parser: passed to - * parseProc and printProc. */ -} Tk_CustomOption; - -/* - * Structure used to specify information for Tk_ConfigureWidget. Each - * structure gives complete information for one option, including - * how the option is specified on the command line, where it appears - * in the option database, etc. - */ - -typedef struct Tk_ConfigSpec { - int type; /* Type of option, such as TK_CONFIG_COLOR; - * see definitions below. Last option in - * table must have type TK_CONFIG_END. */ - char *argvName; /* Switch used to specify option in argv. - * NULL means this spec is part of a group. */ - char *dbName; /* Name for option in option database. */ - char *dbClass; /* Class for option in database. */ - char *defValue; /* Default value for option if not - * specified in command line or database. */ - int offset; /* Where in widget record to store value; - * use Tk_Offset macro to generate values - * for this. */ - int specFlags; /* Any combination of the values defined - * below; other bits are used internally - * by tkConfig.c. */ - Tk_CustomOption *customPtr; /* If type is TK_CONFIG_CUSTOM then this is - * a pointer to info about how to parse and - * print the option. Otherwise it is - * irrelevant. */ -} Tk_ConfigSpec; - -/* - * Type values for Tk_ConfigSpec structures. See the user - * documentation for details. - */ - -#define TK_CONFIG_BOOLEAN 1 -#define TK_CONFIG_INT 2 -#define TK_CONFIG_DOUBLE 3 -#define TK_CONFIG_STRING 4 -#define TK_CONFIG_UID 5 -#define TK_CONFIG_COLOR 6 -#define TK_CONFIG_FONT 7 -#define TK_CONFIG_BITMAP 8 -#define TK_CONFIG_BORDER 9 -#define TK_CONFIG_RELIEF 10 -#define TK_CONFIG_CURSOR 11 -#define TK_CONFIG_ACTIVE_CURSOR 12 -#define TK_CONFIG_JUSTIFY 13 -#define TK_CONFIG_ANCHOR 14 -#define TK_CONFIG_SYNONYM 15 -#define TK_CONFIG_CAP_STYLE 16 -#define TK_CONFIG_JOIN_STYLE 17 -#define TK_CONFIG_PIXELS 18 -#define TK_CONFIG_MM 19 -#define TK_CONFIG_WINDOW 20 -#define TK_CONFIG_CUSTOM 21 -#define TK_CONFIG_END 22 - -/* - * Macro to use to fill in "offset" fields of Tk_ConfigInfos. - * Computes number of bytes from beginning of structure to a - * given field. - */ - -#ifdef offsetof -#define Tk_Offset(type, field) ((int) offsetof(type, field)) -#else -#define Tk_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) -#endif - -/* - * Possible values for flags argument to Tk_ConfigureWidget: - */ - -#define TK_CONFIG_ARGV_ONLY 1 - -/* - * Possible flag values for Tk_ConfigInfo structures. Any bits at - * or above TK_CONFIG_USER_BIT may be used by clients for selecting - * certain entries. Before changing any values here, coordinate with - * tkConfig.c (internal-use-only flags are defined there). - */ - -#define TK_CONFIG_COLOR_ONLY 1 -#define TK_CONFIG_MONO_ONLY 2 -#define TK_CONFIG_NULL_OK 4 -#define TK_CONFIG_DONT_SET_DEFAULT 8 -#define TK_CONFIG_OPTION_SPECIFIED 0x10 -#define TK_CONFIG_USER_BIT 0x100 - -/* - * Enumerated type for describing actions to be taken in response - * to a restrictProc established by Tk_RestrictEvents. - */ - -typedef enum { - TK_DEFER_EVENT, TK_PROCESS_EVENT, TK_DISCARD_EVENT -} Tk_RestrictAction; - -/* - * Priority levels to pass to Tk_AddOption: - */ - -#define TK_WIDGET_DEFAULT_PRIO 20 -#define TK_STARTUP_FILE_PRIO 40 -#define TK_USER_DEFAULT_PRIO 60 -#define TK_INTERACTIVE_PRIO 80 -#define TK_MAX_PRIO 100 - -/* - * Relief values returned by Tk_GetRelief: - */ - -#define TK_RELIEF_RAISED 1 -#define TK_RELIEF_FLAT 2 -#define TK_RELIEF_SUNKEN 4 -#define TK_RELIEF_GROOVE 8 -#define TK_RELIEF_RIDGE 16 -#define TK_RELIEF_SOLID 32 - -/* - * "Which" argument values for Tk_3DBorderGC: - */ - -#define TK_3D_FLAT_GC 1 -#define TK_3D_LIGHT_GC 2 -#define TK_3D_DARK_GC 3 - -/* - * Special EnterNotify/LeaveNotify "mode" for use in events - * generated by tkShare.c. Pick a high enough value that it's - * unlikely to conflict with existing values (like NotifyNormal) - * or any new values defined in the future. - */ - -#define TK_NOTIFY_SHARE 20 - -/* - * Enumerated type for describing a point by which to anchor something: - */ - -typedef enum { - TK_ANCHOR_N, TK_ANCHOR_NE, TK_ANCHOR_E, TK_ANCHOR_SE, - TK_ANCHOR_S, TK_ANCHOR_SW, TK_ANCHOR_W, TK_ANCHOR_NW, - TK_ANCHOR_CENTER -} Tk_Anchor; - -/* - * Enumerated type for describing a style of justification: - */ - -typedef enum { - TK_JUSTIFY_LEFT, TK_JUSTIFY_RIGHT, TK_JUSTIFY_CENTER -} Tk_Justify; - -/* - * The following structure is used by Tk_GetFontMetrics() to return - * information about the properties of a Tk_Font. - */ - -typedef struct Tk_FontMetrics { - int ascent; /* The amount in pixels that the tallest - * letter sticks up above the baseline, plus - * any extra blank space added by the designer - * of the font. */ - int descent; /* The largest amount in pixels that any - * letter sticks below the baseline, plus any - * extra blank space added by the designer of - * the font. */ - int linespace; /* The sum of the ascent and descent. How - * far apart two lines of text in the same - * font should be placed so that none of the - * characters in one line overlap any of the - * characters in the other line. */ -} Tk_FontMetrics; - -/* - * Flags passed to Tk_MeasureChars: - */ - -#define TK_WHOLE_WORDS 1 -#define TK_AT_LEAST_ONE 2 -#define TK_PARTIAL_OK 4 - -/* - * Flags passed to Tk_ComputeTextLayout: - */ - -#define TK_IGNORE_TABS 8 -#define TK_IGNORE_NEWLINES 16 - -/* - * Each geometry manager (the packer, the placer, etc.) is represented - * by a structure of the following form, which indicates procedures - * to invoke in the geometry manager to carry out certain functions. - */ - -typedef void (Tk_GeomRequestProc) _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -typedef void (Tk_GeomLostSlaveProc) _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); - -typedef struct Tk_GeomMgr { - char *name; /* Name of the geometry manager (command - * used to invoke it, or name of widget - * class that allows embedded widgets). */ - Tk_GeomRequestProc *requestProc; - /* Procedure to invoke when a slave's - * requested geometry changes. */ - Tk_GeomLostSlaveProc *lostSlaveProc; - /* Procedure to invoke when a slave is - * taken away from one geometry manager - * by another. NULL means geometry manager - * doesn't care when slaves are lost. */ -} Tk_GeomMgr; - -/* - * Result values returned by Tk_GetScrollInfo: - */ - -#define TK_SCROLL_MOVETO 1 -#define TK_SCROLL_PAGES 2 -#define TK_SCROLL_UNITS 3 -#define TK_SCROLL_ERROR 4 - -/* - *--------------------------------------------------------------------------- - * - * Extensions to the X event set - * - *--------------------------------------------------------------------------- - */ -#define VirtualEvent (LASTEvent) -#define ActivateNotify (LASTEvent + 1) -#define DeactivateNotify (LASTEvent + 2) -#define TK_LASTEVENT (LASTEvent + 3) - -#define VirtualEventMask (1L << 30) -#define ActivateMask (1L << 29) -#define TK_LASTEVENT (LASTEvent + 3) - - -/* - * A virtual event shares most of its fields with the XKeyEvent and - * XButtonEvent structures. 99% of the time a virtual event will be - * an abstraction of a key or button event, so this structure provides - * the most information to the user. The only difference is the changing - * of the detail field for a virtual event so that it holds the name of the - * virtual event being triggered. - */ - -typedef struct { - int type; - unsigned long serial; /* # of last request processed by server */ - Bool send_event; /* True if this came from a SendEvent request */ - Display *display; /* Display the event was read from */ - Window event; /* Window on which event was requested. */ - Window root; /* root window that the event occured on */ - Window subwindow; /* child window */ - Time time; /* milliseconds */ - int x, y; /* pointer x, y coordinates in event window */ - int x_root, y_root; /* coordinates relative to root */ - unsigned int state; /* key or button mask */ - Tk_Uid name; /* Name of virtual event. */ - Bool same_screen; /* same screen flag */ -} XVirtualEvent; - -typedef struct { - int type; - unsigned long serial; /* # of last request processed by server */ - Bool send_event; /* True if this came from a SendEvent request */ - Display *display; /* Display the event was read from */ - Window window; /* Window in which event occurred. */ -} XActivateDeactivateEvent; -typedef XActivateDeactivateEvent XActivateEvent; -typedef XActivateDeactivateEvent XDeactivateEvent; - -/* - *-------------------------------------------------------------- - * - * Macros for querying Tk_Window structures. See the - * manual entries for documentation. - * - *-------------------------------------------------------------- - */ - -#define Tk_Display(tkwin) (((Tk_FakeWin *) (tkwin))->display) -#define Tk_ScreenNumber(tkwin) (((Tk_FakeWin *) (tkwin))->screenNum) -#define Tk_Screen(tkwin) (ScreenOfDisplay(Tk_Display(tkwin), \ - Tk_ScreenNumber(tkwin))) -#define Tk_Depth(tkwin) (((Tk_FakeWin *) (tkwin))->depth) -#define Tk_Visual(tkwin) (((Tk_FakeWin *) (tkwin))->visual) -#define Tk_WindowId(tkwin) (((Tk_FakeWin *) (tkwin))->window) -#define Tk_PathName(tkwin) (((Tk_FakeWin *) (tkwin))->pathName) -#define Tk_Name(tkwin) (((Tk_FakeWin *) (tkwin))->nameUid) -#define Tk_Class(tkwin) (((Tk_FakeWin *) (tkwin))->classUid) -#define Tk_X(tkwin) (((Tk_FakeWin *) (tkwin))->changes.x) -#define Tk_Y(tkwin) (((Tk_FakeWin *) (tkwin))->changes.y) -#define Tk_Width(tkwin) (((Tk_FakeWin *) (tkwin))->changes.width) -#define Tk_Height(tkwin) \ - (((Tk_FakeWin *) (tkwin))->changes.height) -#define Tk_Changes(tkwin) (&((Tk_FakeWin *) (tkwin))->changes) -#define Tk_Attributes(tkwin) (&((Tk_FakeWin *) (tkwin))->atts) -#define Tk_IsEmbedded(tkwin) \ - (((Tk_FakeWin *) (tkwin))->flags & TK_EMBEDDED) -#define Tk_IsContainer(tkwin) \ - (((Tk_FakeWin *) (tkwin))->flags & TK_CONTAINER) -#define Tk_IsMapped(tkwin) \ - (((Tk_FakeWin *) (tkwin))->flags & TK_MAPPED) -#define Tk_IsTopLevel(tkwin) \ - (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) -#define Tk_ReqWidth(tkwin) (((Tk_FakeWin *) (tkwin))->reqWidth) -#define Tk_ReqHeight(tkwin) (((Tk_FakeWin *) (tkwin))->reqHeight) -#define Tk_InternalBorderWidth(tkwin) \ - (((Tk_FakeWin *) (tkwin))->internalBorderWidth) -#define Tk_Parent(tkwin) (((Tk_FakeWin *) (tkwin))->parentPtr) -#define Tk_Colormap(tkwin) (((Tk_FakeWin *) (tkwin))->atts.colormap) - -/* - * The structure below is needed by the macros above so that they can - * access the fields of a Tk_Window. The fields not needed by the macros - * are declared as "dummyX". The structure has its own type in order to - * prevent applications from accessing Tk_Window fields except using - * official macros. WARNING!! The structure definition must be kept - * consistent with the TkWindow structure in tkInt.h. If you change one, - * then change the other. See the declaration in tkInt.h for - * documentation on what the fields are used for internally. - */ - -typedef struct Tk_FakeWin { - Display *display; - char *dummy1; - int screenNum; - Visual *visual; - int depth; - Window window; - char *dummy2; - char *dummy3; - Tk_Window parentPtr; - char *dummy4; - char *dummy5; - char *pathName; - Tk_Uid nameUid; - Tk_Uid classUid; - XWindowChanges changes; - unsigned int dummy6; - XSetWindowAttributes atts; - unsigned long dummy7; - unsigned int flags; - char *dummy8; -#ifdef TK_USE_INPUT_METHODS - XIC dummy9; -#endif /* TK_USE_INPUT_METHODS */ - ClientData *dummy10; - int dummy11; - int dummy12; - char *dummy13; - char *dummy14; - ClientData dummy15; - int reqWidth, reqHeight; - int internalBorderWidth; - char *dummy16; - char *dummy17; - ClientData dummy18; - char *dummy19; -} Tk_FakeWin; - -/* - * Flag values for TkWindow (and Tk_FakeWin) structures are: - * - * TK_MAPPED: 1 means window is currently mapped, - * 0 means unmapped. - * TK_TOP_LEVEL: 1 means this is a top-level window (it - * was or will be created as a child of - * a root window). - * TK_ALREADY_DEAD: 1 means the window is in the process of - * being destroyed already. - * TK_NEED_CONFIG_NOTIFY: 1 means that the window has been reconfigured - * before it was made to exist. At the time of - * making it exist a ConfigureNotify event needs - * to be generated. - * TK_GRAB_FLAG: Used to manage grabs. See tkGrab.c for - * details. - * TK_CHECKED_IC: 1 means we've already tried to get an input - * context for this window; if the ic field - * is NULL it means that there isn't a context - * for the field. - * TK_DONT_DESTROY_WINDOW: 1 means that Tk_DestroyWindow should not - * invoke XDestroyWindow to destroy this widget's - * X window. The flag is set when the window - * has already been destroyed elsewhere (e.g. - * by another application) or when it will be - * destroyed later (e.g. by destroying its - * parent). - * TK_WM_COLORMAP_WINDOW: 1 means that this window has at some time - * appeared in the WM_COLORMAP_WINDOWS property - * for its toplevel, so we have to remove it - * from that property if the window is - * deleted and the toplevel isn't. - * TK_EMBEDDED: 1 means that this window (which must be a - * toplevel) is not a free-standing window but - * rather is embedded in some other application. - * TK_CONTAINER: 1 means that this window is a container, and - * that some other application (either in - * this process or elsewhere) may be - * embedding itself inside the window. - * TK_BOTH_HALVES: 1 means that this window is used for - * application embedding (either as - * container or embedded application), and - * both the containing and embedded halves - * are associated with windows in this - * particular process. - * TK_DEFER_MODAL: 1 means that this window has deferred a modal - * loop until all of the bindings for the current - * event have been invoked. - * TK_WRAPPER: 1 means that this window is the extra - * wrapper window created around a toplevel - * to hold the menubar under Unix. See - * tkUnixWm.c for more information. - * TK_REPARENTED: 1 means that this window has been reparented - * so that as far as the window system is - * concerned it isn't a child of its Tk - * parent. Initially this is used only for - * special Unix menubar windows. - */ - - -#define TK_MAPPED 1 -#define TK_TOP_LEVEL 2 -#define TK_ALREADY_DEAD 4 -#define TK_NEED_CONFIG_NOTIFY 8 -#define TK_GRAB_FLAG 0x10 -#define TK_CHECKED_IC 0x20 -#define TK_DONT_DESTROY_WINDOW 0x40 -#define TK_WM_COLORMAP_WINDOW 0x80 -#define TK_EMBEDDED 0x100 -#define TK_CONTAINER 0x200 -#define TK_BOTH_HALVES 0x400 -#define TK_DEFER_MODAL 0x800 -#define TK_WRAPPER 0x1000 -#define TK_REPARENTED 0x2000 - -/* - *-------------------------------------------------------------- - * - * Procedure prototypes and structures used for defining new canvas - * items: - * - *-------------------------------------------------------------- - */ - -/* - * For each item in a canvas widget there exists one record with - * the following structure. Each actual item is represented by - * a record with the following stuff at its beginning, plus additional - * type-specific stuff after that. - */ - -#define TK_TAG_SPACE 3 - -typedef struct Tk_Item { - int id; /* Unique identifier for this item - * (also serves as first tag for - * item). */ - struct Tk_Item *nextPtr; /* Next in display list of all - * items in this canvas. Later items - * in list are drawn on top of earlier - * ones. */ - Tk_Uid staticTagSpace[TK_TAG_SPACE];/* Built-in space for limited # of - * tags. */ - Tk_Uid *tagPtr; /* Pointer to array of tags. Usually - * points to staticTagSpace, but - * may point to malloc-ed space if - * there are lots of tags. */ - int tagSpace; /* Total amount of tag space available - * at tagPtr. */ - int numTags; /* Number of tag slots actually used - * at *tagPtr. */ - struct Tk_ItemType *typePtr; /* Table of procedures that implement - * this type of item. */ - int x1, y1, x2, y2; /* Bounding box for item, in integer - * canvas units. Set by item-specific - * code and guaranteed to contain every - * pixel drawn in item. Item area - * includes x1 and y1 but not x2 - * and y2. */ - int reserved1; /* This padding is for compatibility */ - char *reserved2; /* with Jan Nijtmans dash patch */ - int reserved3; - char *reserved4; - - /* - *------------------------------------------------------------------ - * Starting here is additional type-specific stuff; see the - * declarations for individual types to see what is part of - * each type. The actual space below is determined by the - * "itemInfoSize" of the type's Tk_ItemType record. - *------------------------------------------------------------------ - */ -} Tk_Item; - -/* - * Records of the following type are used to describe a type of - * item (e.g. lines, circles, etc.) that can form part of a - * canvas widget. - */ - -typedef int Tk_ItemCreateProc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -typedef int Tk_ItemConfigureProc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -typedef int Tk_ItemCoordProc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -typedef void Tk_ItemDeleteProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -typedef void Tk_ItemDisplayProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -typedef double Tk_ItemPointProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); -typedef int Tk_ItemAreaProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -typedef int Tk_ItemPostscriptProc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -typedef void Tk_ItemScaleProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -typedef void Tk_ItemTranslateProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); -typedef int Tk_ItemIndexProc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, char *indexString, - int *indexPtr)); -typedef void Tk_ItemCursorProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int index)); -typedef int Tk_ItemSelectionProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int offset, char *buffer, - int maxBytes)); -typedef void Tk_ItemInsertProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int beforeThis, char *string)); -typedef void Tk_ItemDCharsProc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int first, int last)); - -typedef struct Tk_ItemType { - char *name; /* The name of this type of item, such - * as "line". */ - int itemSize; /* Total amount of space needed for - * item's record. */ - Tk_ItemCreateProc *createProc; /* Procedure to create a new item of - * this type. */ - Tk_ConfigSpec *configSpecs; /* Pointer to array of configuration - * specs for this type. Used for - * returning configuration info. */ - Tk_ItemConfigureProc *configProc; /* Procedure to call to change - * configuration options. */ - Tk_ItemCoordProc *coordProc; /* Procedure to call to get and set - * the item's coordinates. */ - Tk_ItemDeleteProc *deleteProc; /* Procedure to delete existing item of - * this type. */ - Tk_ItemDisplayProc *displayProc; /* Procedure to display items of - * this type. */ - int alwaysRedraw; /* Non-zero means displayProc should - * be called even when the item has - * been moved off-screen. */ - Tk_ItemPointProc *pointProc; /* Computes distance from item to - * a given point. */ - Tk_ItemAreaProc *areaProc; /* Computes whether item is inside, - * outside, or overlapping an area. */ - Tk_ItemPostscriptProc *postscriptProc; - /* Procedure to write a Postscript - * description for items of this - * type. */ - Tk_ItemScaleProc *scaleProc; /* Procedure to rescale items of - * this type. */ - Tk_ItemTranslateProc *translateProc;/* Procedure to translate items of - * this type. */ - Tk_ItemIndexProc *indexProc; /* Procedure to determine index of - * indicated character. NULL if - * item doesn't support indexing. */ - Tk_ItemCursorProc *icursorProc; /* Procedure to set insert cursor pos. - * to just before a given position. */ - Tk_ItemSelectionProc *selectionProc;/* Procedure to return selection (in - * STRING format) when it is in this - * item. */ - Tk_ItemInsertProc *insertProc; /* Procedure to insert something into - * an item. */ - Tk_ItemDCharsProc *dCharsProc; /* Procedure to delete characters - * from an item. */ - struct Tk_ItemType *nextPtr; /* Used to link types together into - * a list. */ - char *reserved1; /* Reserved for future extension. */ - int reserved2; /* Carefully compatible with */ - char *reserved3; /* Jan Nijtmans dash patch */ - char *reserved4; -} Tk_ItemType; - -/* - * The following structure provides information about the selection and - * the insertion cursor. It is needed by only a few items, such as - * those that display text. It is shared by the generic canvas code - * and the item-specific code, but most of the fields should be written - * only by the canvas generic code. - */ - -typedef struct Tk_CanvasTextInfo { - Tk_3DBorder selBorder; /* Border and background for selected - * characters. Read-only to items.*/ - int selBorderWidth; /* Width of border around selection. - * Read-only to items. */ - XColor *selFgColorPtr; /* Foreground color for selected text. - * Read-only to items. */ - Tk_Item *selItemPtr; /* Pointer to selected item. NULL means - * selection isn't in this canvas. - * Writable by items. */ - int selectFirst; /* Index of first selected character. - * Writable by items. */ - int selectLast; /* Index of last selected character. - * Writable by items. */ - Tk_Item *anchorItemPtr; /* Item corresponding to "selectAnchor": - * not necessarily selItemPtr. Read-only - * to items. */ - int selectAnchor; /* Fixed end of selection (i.e. "select to" - * operation will use this as one end of the - * selection). Writable by items. */ - Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion - * cursor. Read-only to items. */ - int insertWidth; /* Total width of insertion cursor. Read-only - * to items. */ - int insertBorderWidth; /* Width of 3-D border around insert cursor. - * Read-only to items. */ - Tk_Item *focusItemPtr; /* Item that currently has the input focus, - * or NULL if no such item. Read-only to - * items. */ - int gotFocus; /* Non-zero means that the canvas widget has - * the input focus. Read-only to items.*/ - int cursorOn; /* Non-zero means that an insertion cursor - * should be displayed in focusItemPtr. - * Read-only to items.*/ -} Tk_CanvasTextInfo; - -/* - *-------------------------------------------------------------- - * - * Procedure prototypes and structures used for managing images: - * - *-------------------------------------------------------------- - */ - -typedef struct Tk_ImageType Tk_ImageType; -typedef int (Tk_ImageCreateProc) _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int argc, char **argv, Tk_ImageType *typePtr, - Tk_ImageMaster master, ClientData *masterDataPtr)); -typedef ClientData (Tk_ImageGetProc) _ANSI_ARGS_((Tk_Window tkwin, - ClientData masterData)); -typedef void (Tk_ImageDisplayProc) _ANSI_ARGS_((ClientData instanceData, - Display *display, Drawable drawable, int imageX, int imageY, - int width, int height, int drawableX, int drawableY)); -typedef void (Tk_ImageFreeProc) _ANSI_ARGS_((ClientData instanceData, - Display *display)); -typedef void (Tk_ImageDeleteProc) _ANSI_ARGS_((ClientData masterData)); -typedef void (Tk_ImageChangedProc) _ANSI_ARGS_((ClientData clientData, - int x, int y, int width, int height, int imageWidth, - int imageHeight)); - -/* - * The following structure represents a particular type of image - * (bitmap, xpm image, etc.). It provides information common to - * all images of that type, such as the type name and a collection - * of procedures in the image manager that respond to various - * events. Each image manager is represented by one of these - * structures. - */ - -struct Tk_ImageType { - char *name; /* Name of image type. */ - Tk_ImageCreateProc *createProc; - /* Procedure to call to create a new image - * of this type. */ - Tk_ImageGetProc *getProc; /* Procedure to call the first time - * Tk_GetImage is called in a new way - * (new visual or screen). */ - Tk_ImageDisplayProc *displayProc; - /* Call to draw image, in response to - * Tk_RedrawImage calls. */ - Tk_ImageFreeProc *freeProc; /* Procedure to call whenever Tk_FreeImage - * is called to release an instance of an - * image. */ - Tk_ImageDeleteProc *deleteProc; - /* Procedure to call to delete image. It - * will not be called until after freeProc - * has been called for each instance of the - * image. */ - struct Tk_ImageType *nextPtr; - /* Next in list of all image types currently - * known. Filled in by Tk, not by image - * manager. */ - char *reserved; /* reserved for future expansion */ -}; - -/* - *-------------------------------------------------------------- - * - * Additional definitions used to manage images of type "photo". - * - *-------------------------------------------------------------- - */ - -/* - * The following type is used to identify a particular photo image - * to be manipulated: - */ - -typedef void *Tk_PhotoHandle; - -/* - * The following structure describes a block of pixels in memory: - */ - -typedef struct Tk_PhotoImageBlock { - unsigned char *pixelPtr; /* Pointer to the first pixel. */ - int width; /* Width of block, in pixels. */ - int height; /* Height of block, in pixels. */ - int pitch; /* Address difference between corresponding - * pixels in successive lines. */ - int pixelSize; /* Address difference between successive - * pixels in the same line. */ - int offset[3]; /* Address differences between the red, green - * and blue components of the pixel and the - * pixel as a whole. */ - int reserved; /* Reserved for extensions (dash patch) */ -} Tk_PhotoImageBlock; - -/* - * Procedure prototypes and structures used in reading and - * writing photo images: - */ - -typedef struct Tk_PhotoImageFormat Tk_PhotoImageFormat; -typedef int (Tk_ImageFileMatchProc) _ANSI_ARGS_((Tcl_Channel chan, - char *fileName, char *formatString, int *widthPtr, int *heightPtr)); -typedef int (Tk_ImageStringMatchProc) _ANSI_ARGS_((char *string, - char *formatString, int *widthPtr, int *heightPtr)); -typedef int (Tk_ImageFileReadProc) _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, char *formatString, - Tk_PhotoHandle imageHandle, int destX, int destY, - int width, int height, int srcX, int srcY)); -typedef int (Tk_ImageStringReadProc) _ANSI_ARGS_((Tcl_Interp *interp, - char *string, char *formatString, Tk_PhotoHandle imageHandle, - int destX, int destY, int width, int height, int srcX, int srcY)); -typedef int (Tk_ImageFileWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, - char *fileName, char *formatString, Tk_PhotoImageBlock *blockPtr)); -typedef int (Tk_ImageStringWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_DString *dataPtr, char *formatString, - Tk_PhotoImageBlock *blockPtr)); - -/* - * The following structure represents a particular file format for - * storing images (e.g., PPM, GIF, JPEG, etc.). It provides information - * to allow image files of that format to be recognized and read into - * a photo image. - */ - -struct Tk_PhotoImageFormat { - char *name; /* Name of image file format */ - Tk_ImageFileMatchProc *fileMatchProc; - /* Procedure to call to determine whether - * an image file matches this format. */ - Tk_ImageStringMatchProc *stringMatchProc; - /* Procedure to call to determine whether - * the data in a string matches this format. */ - Tk_ImageFileReadProc *fileReadProc; - /* Procedure to call to read data from - * an image file into a photo image. */ - Tk_ImageStringReadProc *stringReadProc; - /* Procedure to call to read data from - * a string into a photo image. */ - Tk_ImageFileWriteProc *fileWriteProc; - /* Procedure to call to write data from - * a photo image to a file. */ - Tk_ImageStringWriteProc *stringWriteProc; - /* Procedure to call to obtain a string - * representation of the data in a photo - * image.*/ - struct Tk_PhotoImageFormat *nextPtr; - /* Next in list of all photo image formats - * currently known. Filled in by Tk, not - * by image format handler. */ -}; - -/* - *-------------------------------------------------------------- - * - * The definitions below provide backward compatibility for - * functions and types related to event handling that used to - * be in Tk but have moved to Tcl. - * - *-------------------------------------------------------------- - */ - -#define TK_READABLE TCL_READABLE -#define TK_WRITABLE TCL_WRITABLE -#define TK_EXCEPTION TCL_EXCEPTION - -#define TK_DONT_WAIT TCL_DONT_WAIT -#define TK_X_EVENTS TCL_WINDOW_EVENTS -#define TK_WINDOW_EVENTS TCL_WINDOW_EVENTS -#define TK_FILE_EVENTS TCL_FILE_EVENTS -#define TK_TIMER_EVENTS TCL_TIMER_EVENTS -#define TK_IDLE_EVENTS TCL_IDLE_EVENTS -#define TK_ALL_EVENTS TCL_ALL_EVENTS - -#define Tk_IdleProc Tcl_IdleProc -#define Tk_FileProc Tcl_FileProc -#define Tk_TimerProc Tcl_TimerProc -#define Tk_TimerToken Tcl_TimerToken - -#define Tk_BackgroundError Tcl_BackgroundError -#define Tk_CancelIdleCall Tcl_CancelIdleCall -#define Tk_CreateFileHandler Tcl_CreateFileHandler -#define Tk_CreateTimerHandler Tcl_CreateTimerHandler -#define Tk_DeleteFileHandler Tcl_DeleteFileHandler -#define Tk_DeleteTimerHandler Tcl_DeleteTimerHandler -#define Tk_DoOneEvent Tcl_DoOneEvent -#define Tk_DoWhenIdle Tcl_DoWhenIdle -#define Tk_Sleep Tcl_Sleep - -/* Additional stuff that has moved to Tcl: */ - -#define Tk_AfterCmd Tcl_AfterCmd -#define Tk_EventuallyFree Tcl_EventuallyFree -#define Tk_FreeProc Tcl_FreeProc -#define Tk_Preserve Tcl_Preserve -#define Tk_Release Tcl_Release - -/* - *-------------------------------------------------------------- - * - * Additional procedure types defined by Tk. - * - *-------------------------------------------------------------- - */ - -typedef int (Tk_ErrorProc) _ANSI_ARGS_((ClientData clientData, - XErrorEvent *errEventPtr)); -typedef void (Tk_EventProc) _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -typedef int (Tk_GenericProc) _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -typedef int (Tk_GetSelProc) _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *portion)); -typedef void (Tk_LostSelProc) _ANSI_ARGS_((ClientData clientData)); -typedef Tk_RestrictAction (Tk_RestrictProc) _ANSI_ARGS_(( - ClientData clientData, XEvent *eventPtr)); -typedef int (Tk_SelectionProc) _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); - -/* - *-------------------------------------------------------------- - * - * Exported procedures and variables. - * - *-------------------------------------------------------------- - */ - -EXTERN XColor * Tk_3DBorderColor _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN GC Tk_3DBorderGC _ANSI_ARGS_((Tk_Window tkwin, - Tk_3DBorder border, int which)); -EXTERN void Tk_3DHorizontalBevel _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int leftIn, - int rightIn, int topBevel, int relief)); -EXTERN void Tk_3DVerticalBevel _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int leftBevel, - int relief)); -EXTERN void Tk_AddOption _ANSI_ARGS_((Tk_Window tkwin, char *name, - char *value, int priority)); -EXTERN void Tk_BindEvent _ANSI_ARGS_((Tk_BindingTable bindingTable, - XEvent *eventPtr, Tk_Window tkwin, int numObjects, - ClientData *objectPtr)); -EXTERN void Tk_CanvasDrawableCoords _ANSI_ARGS_((Tk_Canvas canvas, - double x, double y, short *drawableXPtr, - short *drawableYPtr)); -EXTERN void Tk_CanvasEventuallyRedraw _ANSI_ARGS_(( - Tk_Canvas canvas, int x1, int y1, int x2, - int y2)); -EXTERN int Tk_CanvasGetCoord _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, char *string, - double *doublePtr)); -EXTERN Tk_CanvasTextInfo *Tk_CanvasGetTextInfo _ANSI_ARGS_((Tk_Canvas canvas)); -EXTERN int Tk_CanvasPsBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Pixmap bitmap, int x, int y, - int width, int height)); -EXTERN int Tk_CanvasPsColor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, XColor *colorPtr)); -EXTERN int Tk_CanvasPsFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Font font)); -EXTERN void Tk_CanvasPsPath _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, double *coordPtr, int numPoints)); -EXTERN int Tk_CanvasPsStipple _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Pixmap bitmap)); -EXTERN double Tk_CanvasPsY _ANSI_ARGS_((Tk_Canvas canvas, double y)); -EXTERN void Tk_CanvasSetStippleOrigin _ANSI_ARGS_(( - Tk_Canvas canvas, GC gc)); -EXTERN int Tk_CanvasTagsParseProc _ANSI_ARGS_(( - ClientData clientData, Tcl_Interp *interp, - Tk_Window tkwin, char *value, char *widgRec, - int offset)); -EXTERN char * Tk_CanvasTagsPrintProc _ANSI_ARGS_(( - ClientData clientData, Tk_Window tkwin, - char *widgRec, int offset, - Tcl_FreeProc **freeProcPtr)); -EXTERN Tk_Window Tk_CanvasTkwin _ANSI_ARGS_((Tk_Canvas canvas)); -EXTERN void Tk_CanvasWindowCoords _ANSI_ARGS_((Tk_Canvas canvas, - double x, double y, short *screenXPtr, - short *screenYPtr)); -EXTERN void Tk_ChangeWindowAttributes _ANSI_ARGS_((Tk_Window tkwin, - unsigned long valueMask, - XSetWindowAttributes *attsPtr)); -EXTERN int Tk_CharBbox _ANSI_ARGS_((Tk_TextLayout layout, - int index, int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -EXTERN void Tk_ClearSelection _ANSI_ARGS_((Tk_Window tkwin, - Atom selection)); -EXTERN int Tk_ClipboardAppend _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Atom target, Atom format, - char* buffer)); -EXTERN int Tk_ClipboardClear _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN int Tk_ConfigureInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - char *widgRec, char *argvName, int flags)); -EXTERN int Tk_ConfigureValue _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - char *widgRec, char *argvName, int flags)); -EXTERN int Tk_ConfigureWidget _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - int argc, char **argv, char *widgRec, - int flags)); -EXTERN void Tk_ConfigureWindow _ANSI_ARGS_((Tk_Window tkwin, - unsigned int valueMask, XWindowChanges *valuePtr)); -EXTERN Tk_TextLayout Tk_ComputeTextLayout _ANSI_ARGS_((Tk_Font font, - CONST char *string, int numChars, int wrapLength, - Tk_Justify justify, int flags, int *widthPtr, - int *heightPtr)); -EXTERN Tk_Window Tk_CoordsToWindow _ANSI_ARGS_((int rootX, int rootY, - Tk_Window tkwin)); -EXTERN unsigned long Tk_CreateBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString, char *command, int append)); -EXTERN Tk_BindingTable Tk_CreateBindingTable _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN Tk_ErrorHandler Tk_CreateErrorHandler _ANSI_ARGS_((Display *display, - int errNum, int request, int minorCode, - Tk_ErrorProc *errorProc, ClientData clientData)); -EXTERN void Tk_CreateEventHandler _ANSI_ARGS_((Tk_Window token, - unsigned long mask, Tk_EventProc *proc, - ClientData clientData)); -EXTERN void Tk_CreateGenericHandler _ANSI_ARGS_(( - Tk_GenericProc *proc, ClientData clientData)); -EXTERN void Tk_CreateImageType _ANSI_ARGS_(( - Tk_ImageType *typePtr)); -EXTERN void Tk_CreateItemType _ANSI_ARGS_((Tk_ItemType *typePtr)); -EXTERN void Tk_CreatePhotoImageFormat _ANSI_ARGS_(( - Tk_PhotoImageFormat *formatPtr)); -EXTERN void Tk_CreateSelHandler _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Atom target, - Tk_SelectionProc *proc, ClientData clientData, - Atom format)); -EXTERN Tk_Window Tk_CreateWindow _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window parent, char *name, char *screenName)); -EXTERN Tk_Window Tk_CreateWindowFromPath _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_Window tkwin, - char *pathName, char *screenName)); -EXTERN int Tk_DefineBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Uid name, char *source, int width, - int height)); -EXTERN void Tk_DefineCursor _ANSI_ARGS_((Tk_Window window, - Tk_Cursor cursor)); -EXTERN void Tk_DeleteAllBindings _ANSI_ARGS_(( - Tk_BindingTable bindingTable, ClientData object)); -EXTERN int Tk_DeleteBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString)); -EXTERN void Tk_DeleteBindingTable _ANSI_ARGS_(( - Tk_BindingTable bindingTable)); -EXTERN void Tk_DeleteErrorHandler _ANSI_ARGS_(( - Tk_ErrorHandler handler)); -EXTERN void Tk_DeleteEventHandler _ANSI_ARGS_((Tk_Window token, - unsigned long mask, Tk_EventProc *proc, - ClientData clientData)); -EXTERN void Tk_DeleteGenericHandler _ANSI_ARGS_(( - Tk_GenericProc *proc, ClientData clientData)); -EXTERN void Tk_DeleteImage _ANSI_ARGS_((Tcl_Interp *interp, - char *name)); -EXTERN void Tk_DeleteSelHandler _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Atom target)); -EXTERN void Tk_DestroyWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN char * Tk_DisplayName _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN int Tk_DistanceToTextLayout _ANSI_ARGS_(( - Tk_TextLayout layout, int x, int y)); -EXTERN void Tk_Draw3DPolygon _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, - XPoint *pointPtr, int numPoints, int borderWidth, - int leftRelief)); -EXTERN void Tk_Draw3DRectangle _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int borderWidth, - int relief)); -EXTERN void Tk_DrawChars _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_Font tkfont, - CONST char *source, int numChars, int x, - int y)); -EXTERN void Tk_DrawFocusHighlight _ANSI_ARGS_((Tk_Window tkwin, - GC gc, int width, Drawable drawable)); -EXTERN void Tk_DrawTextLayout _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_TextLayout layout, - int x, int y, int firstChar, int lastChar)); -EXTERN void Tk_Fill3DPolygon _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, - XPoint *pointPtr, int numPoints, int borderWidth, - int leftRelief)); -EXTERN void Tk_Fill3DRectangle _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int borderWidth, - int relief)); -EXTERN Tk_PhotoHandle Tk_FindPhoto _ANSI_ARGS_((Tcl_Interp *interp, - char *imageName)); -EXTERN Font Tk_FontId _ANSI_ARGS_((Tk_Font font)); -EXTERN void Tk_Free3DBorder _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN void Tk_FreeBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap)); -EXTERN void Tk_FreeColor _ANSI_ARGS_((XColor *colorPtr)); -EXTERN void Tk_FreeColormap _ANSI_ARGS_((Display *display, - Colormap colormap)); -EXTERN void Tk_FreeCursor _ANSI_ARGS_((Display *display, - Tk_Cursor cursor)); -EXTERN void Tk_FreeFont _ANSI_ARGS_((Tk_Font)); -EXTERN void Tk_FreeGC _ANSI_ARGS_((Display *display, GC gc)); -EXTERN void Tk_FreeImage _ANSI_ARGS_((Tk_Image image)); -EXTERN void Tk_FreeOptions _ANSI_ARGS_((Tk_ConfigSpec *specs, - char *widgRec, Display *display, int needFlags)); -EXTERN void Tk_FreePixmap _ANSI_ARGS_((Display *display, - Pixmap pixmap)); -EXTERN void Tk_FreeTextLayout _ANSI_ARGS_(( - Tk_TextLayout textLayout)); -EXTERN void Tk_FreeXId _ANSI_ARGS_((Display *display, XID xid)); -EXTERN GC Tk_GCForColor _ANSI_ARGS_((XColor *colorPtr, - Drawable drawable)); -EXTERN void Tk_GeometryRequest _ANSI_ARGS_((Tk_Window tkwin, - int reqWidth, int reqHeight)); -EXTERN Tk_3DBorder Tk_Get3DBorder _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid colorName)); -EXTERN void Tk_GetAllBindings _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object)); -EXTERN int Tk_GetAnchor _ANSI_ARGS_((Tcl_Interp *interp, - char *string, Tk_Anchor *anchorPtr)); -EXTERN char * Tk_GetAtomName _ANSI_ARGS_((Tk_Window tkwin, - Atom atom)); -EXTERN char * Tk_GetBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString)); -EXTERN Pixmap Tk_GetBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN Pixmap Tk_GetBitmapFromData _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *source, - int width, int height)); -EXTERN int Tk_GetCapStyle _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *capPtr)); -EXTERN XColor * Tk_GetColor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid name)); -EXTERN XColor * Tk_GetColorByValue _ANSI_ARGS_((Tk_Window tkwin, - XColor *colorPtr)); -EXTERN Colormap Tk_GetColormap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string)); -EXTERN Tk_Cursor Tk_GetCursor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN Tk_Cursor Tk_GetCursorFromData _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *source, char *mask, - int width, int height, int xHot, int yHot, - Tk_Uid fg, Tk_Uid bg)); -EXTERN Tk_Font Tk_GetFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, CONST char *string)); -EXTERN Tk_Font Tk_GetFontFromObj _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *objPtr)); -EXTERN void Tk_GetFontMetrics _ANSI_ARGS_((Tk_Font font, - Tk_FontMetrics *fmPtr)); -EXTERN GC Tk_GetGC _ANSI_ARGS_((Tk_Window tkwin, - unsigned long valueMask, XGCValues *valuePtr)); -EXTERN Tk_Image Tk_GetImage _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *name, - Tk_ImageChangedProc *changeProc, - ClientData clientData)); -EXTERN ClientData Tk_GetImageMasterData _ANSI_ARGS_ ((Tcl_Interp *interp, - char *name, Tk_ImageType **typePtrPtr)); -EXTERN Tk_ItemType * Tk_GetItemTypes _ANSI_ARGS_((void)); -EXTERN int Tk_GetJoinStyle _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *joinPtr)); -EXTERN int Tk_GetJustify _ANSI_ARGS_((Tcl_Interp *interp, - char *string, Tk_Justify *justifyPtr)); -EXTERN int Tk_GetNumMainWindows _ANSI_ARGS_((void)); -EXTERN Tk_Uid Tk_GetOption _ANSI_ARGS_((Tk_Window tkwin, char *name, - char *className)); -EXTERN int Tk_GetPixels _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, int *intPtr)); -EXTERN Pixmap Tk_GetPixmap _ANSI_ARGS_((Display *display, Drawable d, - int width, int height, int depth)); -EXTERN int Tk_GetRelief _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int *reliefPtr)); -EXTERN void Tk_GetRootCoords _ANSI_ARGS_ ((Tk_Window tkwin, - int *xPtr, int *yPtr)); -EXTERN int Tk_GetScrollInfo _ANSI_ARGS_((Tcl_Interp *interp, - int argc, char **argv, double *dblPtr, - int *intPtr)); -EXTERN int Tk_GetScreenMM _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, double *doublePtr)); -EXTERN int Tk_GetSelection _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Atom selection, Atom target, - Tk_GetSelProc *proc, ClientData clientData)); -EXTERN Tk_Uid Tk_GetUid _ANSI_ARGS_((CONST char *string)); -EXTERN Visual * Tk_GetVisual _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, int *depthPtr, - Colormap *colormapPtr)); -EXTERN void Tk_GetVRootGeometry _ANSI_ARGS_((Tk_Window tkwin, - int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -EXTERN int Tk_Grab _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int grabGlobal)); -EXTERN void Tk_HandleEvent _ANSI_ARGS_((XEvent *eventPtr)); -EXTERN Tk_Window Tk_IdToWindow _ANSI_ARGS_((Display *display, - Window window)); -EXTERN void Tk_ImageChanged _ANSI_ARGS_(( - Tk_ImageMaster master, int x, int y, - int width, int height, int imageWidth, - int imageHeight)); -EXTERN int Tk_Init _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN Atom Tk_InternAtom _ANSI_ARGS_((Tk_Window tkwin, - char *name)); -EXTERN int Tk_IntersectTextLayout _ANSI_ARGS_(( - Tk_TextLayout layout, int x, int y, int width, - int height)); -EXTERN void Tk_Main _ANSI_ARGS_((int argc, char **argv, - Tcl_AppInitProc *appInitProc)); -EXTERN void Tk_MainLoop _ANSI_ARGS_((void)); -EXTERN void Tk_MaintainGeometry _ANSI_ARGS_((Tk_Window slave, - Tk_Window master, int x, int y, int width, - int height)); -EXTERN Tk_Window Tk_MainWindow _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void Tk_MakeWindowExist _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_ManageGeometry _ANSI_ARGS_((Tk_Window tkwin, - Tk_GeomMgr *mgrPtr, ClientData clientData)); -EXTERN void Tk_MapWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN int Tk_MeasureChars _ANSI_ARGS_((Tk_Font tkfont, - CONST char *source, int maxChars, int maxPixels, - int flags, int *lengthPtr)); -EXTERN void Tk_MoveResizeWindow _ANSI_ARGS_((Tk_Window tkwin, - int x, int y, int width, int height)); -EXTERN void Tk_MoveWindow _ANSI_ARGS_((Tk_Window tkwin, int x, - int y)); -EXTERN void Tk_MoveToplevelWindow _ANSI_ARGS_((Tk_Window tkwin, - int x, int y)); -EXTERN char * Tk_NameOf3DBorder _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN char * Tk_NameOfAnchor _ANSI_ARGS_((Tk_Anchor anchor)); -EXTERN char * Tk_NameOfBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap)); -EXTERN char * Tk_NameOfCapStyle _ANSI_ARGS_((int cap)); -EXTERN char * Tk_NameOfColor _ANSI_ARGS_((XColor *colorPtr)); -EXTERN char * Tk_NameOfCursor _ANSI_ARGS_((Display *display, - Tk_Cursor cursor)); -EXTERN char * Tk_NameOfFont _ANSI_ARGS_((Tk_Font font)); -EXTERN char * Tk_NameOfImage _ANSI_ARGS_(( - Tk_ImageMaster imageMaster)); -EXTERN char * Tk_NameOfJoinStyle _ANSI_ARGS_((int join)); -EXTERN char * Tk_NameOfJustify _ANSI_ARGS_((Tk_Justify justify)); -EXTERN char * Tk_NameOfRelief _ANSI_ARGS_((int relief)); -EXTERN Tk_Window Tk_NameToWindow _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName, Tk_Window tkwin)); -EXTERN void Tk_OwnSelection _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Tk_LostSelProc *proc, - ClientData clientData)); -EXTERN int Tk_ParseArgv _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int *argcPtr, char **argv, - Tk_ArgvInfo *argTable, int flags)); -EXTERN void Tk_PhotoPutBlock _ANSI_ARGS_((Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height)); -EXTERN void Tk_PhotoPutZoomedBlock _ANSI_ARGS_(( - Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height, int zoomX, int zoomY, - int subsampleX, int subsampleY)); -EXTERN int Tk_PhotoGetImage _ANSI_ARGS_((Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr)); -EXTERN void Tk_PhotoBlank _ANSI_ARGS_((Tk_PhotoHandle handle)); -EXTERN void Tk_PhotoExpand _ANSI_ARGS_((Tk_PhotoHandle handle, - int width, int height )); -EXTERN void Tk_PhotoGetSize _ANSI_ARGS_((Tk_PhotoHandle handle, - int *widthPtr, int *heightPtr)); -EXTERN void Tk_PhotoSetSize _ANSI_ARGS_((Tk_PhotoHandle handle, - int width, int height)); -EXTERN int Tk_PointToChar _ANSI_ARGS_((Tk_TextLayout layout, - int x, int y)); -EXTERN int Tk_PostscriptFontName _ANSI_ARGS_((Tk_Font tkfont, - Tcl_DString *dsPtr)); -EXTERN void Tk_PreserveColormap _ANSI_ARGS_((Display *display, - Colormap colormap)); -EXTERN void Tk_QueueWindowEvent _ANSI_ARGS_((XEvent *eventPtr, - Tcl_QueuePosition position)); -EXTERN void Tk_RedrawImage _ANSI_ARGS_((Tk_Image image, int imageX, - int imageY, int width, int height, - Drawable drawable, int drawableX, int drawableY)); -EXTERN void Tk_ResizeWindow _ANSI_ARGS_((Tk_Window tkwin, - int width, int height)); -EXTERN int Tk_RestackWindow _ANSI_ARGS_((Tk_Window tkwin, - int aboveBelow, Tk_Window other)); -EXTERN Tk_RestrictProc *Tk_RestrictEvents _ANSI_ARGS_((Tk_RestrictProc *proc, - ClientData arg, ClientData *prevArgPtr)); -EXTERN int Tk_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN char * Tk_SetAppName _ANSI_ARGS_((Tk_Window tkwin, - char *name)); -EXTERN void Tk_SetBackgroundFromBorder _ANSI_ARGS_(( - Tk_Window tkwin, Tk_3DBorder border)); -EXTERN void Tk_SetClass _ANSI_ARGS_((Tk_Window tkwin, - char *className)); -EXTERN void Tk_SetGrid _ANSI_ARGS_((Tk_Window tkwin, - int reqWidth, int reqHeight, int gridWidth, - int gridHeight)); -EXTERN void Tk_SetInternalBorder _ANSI_ARGS_((Tk_Window tkwin, - int width)); -EXTERN void Tk_SetWindowBackground _ANSI_ARGS_((Tk_Window tkwin, - unsigned long pixel)); -EXTERN void Tk_SetWindowBackgroundPixmap _ANSI_ARGS_(( - Tk_Window tkwin, Pixmap pixmap)); -EXTERN void Tk_SetWindowBorder _ANSI_ARGS_((Tk_Window tkwin, - unsigned long pixel)); -EXTERN void Tk_SetWindowBorderWidth _ANSI_ARGS_((Tk_Window tkwin, - int width)); -EXTERN void Tk_SetWindowBorderPixmap _ANSI_ARGS_((Tk_Window tkwin, - Pixmap pixmap)); -EXTERN void Tk_SetWindowColormap _ANSI_ARGS_((Tk_Window tkwin, - Colormap colormap)); -EXTERN int Tk_SetWindowVisual _ANSI_ARGS_((Tk_Window tkwin, - Visual *visual, int depth, - Colormap colormap)); -EXTERN void Tk_SizeOfBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap, int *widthPtr, - int *heightPtr)); -EXTERN void Tk_SizeOfImage _ANSI_ARGS_((Tk_Image image, - int *widthPtr, int *heightPtr)); -EXTERN int Tk_StrictMotif _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_TextLayoutToPostscript _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_TextLayout layout)); -EXTERN int Tk_TextWidth _ANSI_ARGS_((Tk_Font font, - CONST char *string, int numChars)); -EXTERN void Tk_UndefineCursor _ANSI_ARGS_((Tk_Window window)); -EXTERN void Tk_UnderlineChars _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_Font tkfont, - CONST char *source, int x, int y, int firstChar, - int lastChar)); -EXTERN void Tk_UnderlineTextLayout _ANSI_ARGS_(( - Display *display, Drawable drawable, GC gc, - Tk_TextLayout layout, int x, int y, - int underline)); -EXTERN void Tk_Ungrab _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UnmaintainGeometry _ANSI_ARGS_((Tk_Window slave, - Tk_Window master)); -EXTERN void Tk_UnmapWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UnsetGrid _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UpdatePointer _ANSI_ARGS_((Tk_Window tkwin, - int x, int y, int state)); - -/* - * Tcl commands exported by Tk: - */ - -EXTERN int Tk_AfterCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_BellCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_BindCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_BindtagsCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ButtonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_CanvasCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_CheckbuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ClipboardCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ChooseColorCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ChooseFontCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_DestroyCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_EntryCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_EventCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FileeventCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FrameCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FocusCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FontObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_GetOpenFileCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GetSaveFileCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GrabCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GridCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ImageCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_LabelCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ListboxCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_LowerCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MenuCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MenubuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MessageBoxCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MessageCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_OptionCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_PackCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_PlaceCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_RadiobuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_RaiseCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ScaleCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ScrollbarCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_SelectionCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_SendCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_TextCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_TkObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_TkwaitCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ToplevelCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_UpdateCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_WinfoObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_WmCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); - -#endif /* RESOURCE_INCLUDED */ - -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TK */ diff --git a/generic/tk3d.c b/generic/tk3d.c deleted file mode 100644 index ae049c9..0000000 --- a/generic/tk3d.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * tk3d.c -- - * - * This module provides procedures to draw borders in - * the three-dimensional Motif style. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tk3d.c,v 1.2 1998/09/14 18:23:02 stanton Exp $ - */ - -#include <tk3d.h> - -/* - * Hash table to map from a border's values (color, etc.) to a - * Border structure for those values. - */ - -static Tcl_HashTable borderTable; -typedef struct { - Tk_Uid colorName; /* Color for border. */ - Colormap colormap; /* Colormap used for allocating border - * colors. */ - Screen *screen; /* Screen on which border will be drawn. */ -} BorderKey; - -static int initialized = 0; /* 0 means static structures haven't - * been initialized yet. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static void BorderInit _ANSI_ARGS_((void)); -static int Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr, - XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr)); -static void ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr, - int distance, XPoint *p3Ptr)); - -/* - *-------------------------------------------------------------- - * - * Tk_Get3DBorder -- - * - * Create a data structure for displaying a 3-D border. - * - * Results: - * The return value is a token for a data structure - * describing a 3-D border. This token may be passed - * to Tk_Draw3DRectangle and Tk_Free3DBorder. If an - * error prevented the border from being created then - * NULL is returned and an error message will be left - * in interp->result. - * - * Side effects: - * Data structures, graphics contexts, etc. are allocated. - * It is the caller's responsibility to eventually call - * Tk_Free3DBorder to release the resources. - * - *-------------------------------------------------------------- - */ - -Tk_3DBorder -Tk_Get3DBorder(interp, tkwin, colorName) - Tcl_Interp *interp; /* Place to store an error message. */ - Tk_Window tkwin; /* Token for window in which border will - * be drawn. */ - Tk_Uid colorName; /* String giving name of color - * for window background. */ -{ - BorderKey key; - Tcl_HashEntry *hashPtr; - register TkBorder *borderPtr; - int new; - XGCValues gcValues; - - if (!initialized) { - BorderInit(); - } - - /* - * First, check to see if there's already a border that will work - * for this request. - */ - - key.colorName = colorName; - key.colormap = Tk_Colormap(tkwin); - key.screen = Tk_Screen(tkwin); - - hashPtr = Tcl_CreateHashEntry(&borderTable, (char *) &key, &new); - if (!new) { - borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr); - borderPtr->refCount++; - } else { - XColor *bgColorPtr; - - /* - * No satisfactory border exists yet. Initialize a new one. - */ - - bgColorPtr = Tk_GetColor(interp, tkwin, colorName); - if (bgColorPtr == NULL) { - Tcl_DeleteHashEntry(hashPtr); - return NULL; - } - - borderPtr = TkpGetBorder(); - borderPtr->screen = Tk_Screen(tkwin); - borderPtr->visual = Tk_Visual(tkwin); - borderPtr->depth = Tk_Depth(tkwin); - borderPtr->colormap = key.colormap; - borderPtr->refCount = 1; - borderPtr->bgColorPtr = bgColorPtr; - borderPtr->darkColorPtr = NULL; - borderPtr->lightColorPtr = NULL; - borderPtr->shadow = None; - borderPtr->bgGC = None; - borderPtr->darkGC = None; - borderPtr->lightGC = None; - borderPtr->hashPtr = hashPtr; - Tcl_SetHashValue(hashPtr, borderPtr); - - /* - * Create the information for displaying the background color, - * but delay the allocation of shadows until they are actually - * needed for drawing. - */ - - gcValues.foreground = borderPtr->bgColorPtr->pixel; - borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues); - } - return (Tk_3DBorder) borderPtr; -} - -/* - *-------------------------------------------------------------- - * - * Tk_Draw3DRectangle -- - * - * Draw a 3-D border at a given place in a given window. - * - * Results: - * None. - * - * Side effects: - * A 3-D border will be drawn in the indicated drawable. - * The outside edges of the border will be determined by x, - * y, width, and height. The inside edges of the border - * will be determined by the borderWidth argument. - * - *-------------------------------------------------------------- - */ - -void -Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, height, - borderWidth, relief) - Tk_Window tkwin; /* Window for which border was allocated. */ - Drawable drawable; /* X window or pixmap in which to draw. */ - Tk_3DBorder border; /* Token for border to draw. */ - int x, y, width, height; /* Outside area of region in - * which border will be drawn. */ - int borderWidth; /* Desired width for border, in - * pixels. */ - int relief; /* Type of relief: TK_RELIEF_RAISED, - * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */ -{ - if (width < 2*borderWidth) { - borderWidth = width/2; - } - if (height < 2*borderWidth) { - borderWidth = height/2; - } - Tk_3DVerticalBevel(tkwin, drawable, border, x, y, borderWidth, height, - 1, relief); - Tk_3DVerticalBevel(tkwin, drawable, border, x+width-borderWidth, y, - borderWidth, height, 0, relief); - Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, borderWidth, - 1, 1, 1, relief); - Tk_3DHorizontalBevel(tkwin, drawable, border, x, y+height-borderWidth, - width, borderWidth, 0, 0, 0, relief); -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOf3DBorder -- - * - * Given a border, return a textual string identifying the - * border's color. - * - * Results: - * The return value is the string that was used to create - * the border. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOf3DBorder(border) - Tk_3DBorder border; /* Token for border. */ -{ - TkBorder *borderPtr = (TkBorder *) border; - - return ((BorderKey *) borderPtr->hashPtr->key.words)->colorName; -} - -/* - *-------------------------------------------------------------------- - * - * Tk_3DBorderColor -- - * - * Given a 3D border, return the X color used for the "flat" - * surfaces. - * - * Results: - * Returns the color used drawing flat surfaces with the border. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------- - */ -XColor * -Tk_3DBorderColor(border) - Tk_3DBorder border; /* Border whose color is wanted. */ -{ - return(((TkBorder *) border)->bgColorPtr); -} - -/* - *-------------------------------------------------------------------- - * - * Tk_3DBorderGC -- - * - * Given a 3D border, returns one of the graphics contexts used to - * draw the border. - * - * Results: - * Returns the graphics context given by the "which" argument. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------- - */ -GC -Tk_3DBorderGC(tkwin, border, which) - Tk_Window tkwin; /* Window for which border was allocated. */ - Tk_3DBorder border; /* Border whose GC is wanted. */ - int which; /* Selects one of the border's 3 GC's: - * TK_3D_FLAT_GC, TK_3D_LIGHT_GC, or - * TK_3D_DARK_GC. */ -{ - TkBorder * borderPtr = (TkBorder *) border; - - if ((borderPtr->lightGC == None) && (which != TK_3D_FLAT_GC)) { - TkpGetShadows(borderPtr, tkwin); - } - if (which == TK_3D_FLAT_GC) { - return borderPtr->bgGC; - } else if (which == TK_3D_LIGHT_GC) { - return borderPtr->lightGC; - } else if (which == TK_3D_DARK_GC){ - return borderPtr->darkGC; - } - panic("bogus \"which\" value in Tk_3DBorderGC"); - - /* - * The code below will never be executed, but it's needed to - * keep compilers happy. - */ - - return (GC) None; -} - -/* - *-------------------------------------------------------------- - * - * Tk_Free3DBorder -- - * - * This procedure is called when a 3D border is no longer - * needed. It frees the resources associated with the - * border. After this call, the caller should never again - * use the "border" token. - * - * Results: - * None. - * - * Side effects: - * Resources are freed. - * - *-------------------------------------------------------------- - */ - -void -Tk_Free3DBorder(border) - Tk_3DBorder border; /* Token for border to be released. */ -{ - register TkBorder *borderPtr = (TkBorder *) border; - Display *display = DisplayOfScreen(borderPtr->screen); - - borderPtr->refCount--; - if (borderPtr->refCount == 0) { - TkpFreeBorder(borderPtr); - if (borderPtr->bgColorPtr != NULL) { - Tk_FreeColor(borderPtr->bgColorPtr); - } - if (borderPtr->darkColorPtr != NULL) { - Tk_FreeColor(borderPtr->darkColorPtr); - } - if (borderPtr->lightColorPtr != NULL) { - Tk_FreeColor(borderPtr->lightColorPtr); - } - if (borderPtr->shadow != None) { - Tk_FreeBitmap(display, borderPtr->shadow); - } - if (borderPtr->bgGC != None) { - Tk_FreeGC(display, borderPtr->bgGC); - } - if (borderPtr->darkGC != None) { - Tk_FreeGC(display, borderPtr->darkGC); - } - if (borderPtr->lightGC != None) { - Tk_FreeGC(display, borderPtr->lightGC); - } - Tcl_DeleteHashEntry(borderPtr->hashPtr); - ckfree((char *) borderPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SetBackgroundFromBorder -- - * - * Change the background of a window to one appropriate for a given - * 3-D border. - * - * Results: - * None. - * - * Side effects: - * Tkwin's background gets modified. - * - *---------------------------------------------------------------------- - */ - -void -Tk_SetBackgroundFromBorder(tkwin, border) - Tk_Window tkwin; /* Window whose background is to be set. */ - Tk_3DBorder border; /* Token for border. */ -{ - register TkBorder *borderPtr = (TkBorder *) border; - - Tk_SetWindowBackground(tkwin, borderPtr->bgColorPtr->pixel); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetRelief -- - * - * Parse a relief description and return the corresponding - * relief value, or an error. - * - * Results: - * A standard Tcl return value. If all goes well then - * *reliefPtr is filled in with one of the values - * TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_GetRelief(interp, name, reliefPtr) - Tcl_Interp *interp; /* For error messages. */ - char *name; /* Name of a relief type. */ - int *reliefPtr; /* Where to store converted relief. */ -{ - char c; - size_t length; - - c = name[0]; - length = strlen(name); - if ((c == 'f') && (strncmp(name, "flat", length) == 0)) { - *reliefPtr = TK_RELIEF_FLAT; - } else if ((c == 'g') && (strncmp(name, "groove", length) == 0) - && (length >= 2)) { - *reliefPtr = TK_RELIEF_GROOVE; - } else if ((c == 'r') && (strncmp(name, "raised", length) == 0) - && (length >= 2)) { - *reliefPtr = TK_RELIEF_RAISED; - } else if ((c == 'r') && (strncmp(name, "ridge", length) == 0)) { - *reliefPtr = TK_RELIEF_RIDGE; - } else if ((c == 's') && (strncmp(name, "solid", length) == 0)) { - *reliefPtr = TK_RELIEF_SOLID; - } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) { - *reliefPtr = TK_RELIEF_SUNKEN; - } else { - sprintf(interp->result, "bad relief type \"%.50s\": must be %s", - name, "flat, groove, raised, ridge, solid, or sunken"); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfRelief -- - * - * Given a relief value, produce a string describing that - * relief value. - * - * Results: - * The return value is a static string that is equivalent - * to relief. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfRelief(relief) - int relief; /* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED, - * or TK_RELIEF_SUNKEN. */ -{ - if (relief == TK_RELIEF_FLAT) { - return "flat"; - } else if (relief == TK_RELIEF_SUNKEN) { - return "sunken"; - } else if (relief == TK_RELIEF_RAISED) { - return "raised"; - } else if (relief == TK_RELIEF_GROOVE) { - return "groove"; - } else if (relief == TK_RELIEF_RIDGE) { - return "ridge"; - } else if (relief == TK_RELIEF_SOLID) { - return "solid"; - } else { - return "unknown relief"; - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_Draw3DPolygon -- - * - * Draw a border with 3-D appearance around the edge of a - * given polygon. - * - * Results: - * None. - * - * Side effects: - * Information is drawn in "drawable" in the form of a - * 3-D border borderWidth units width wide on the left - * of the trajectory given by pointPtr and numPoints (or - * -borderWidth units wide on the right side, if borderWidth - * is negative). - * - *-------------------------------------------------------------- - */ - -void -Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints, - borderWidth, leftRelief) - Tk_Window tkwin; /* Window for which border was allocated. */ - Drawable drawable; /* X window or pixmap in which to draw. */ - Tk_3DBorder border; /* Token for border to draw. */ - XPoint *pointPtr; /* Array of points describing - * polygon. All points must be - * absolute (CoordModeOrigin). */ - int numPoints; /* Number of points at *pointPtr. */ - int borderWidth; /* Width of border, measured in - * pixels to the left of the polygon's - * trajectory. May be negative. */ - int leftRelief; /* TK_RELIEF_RAISED or - * TK_RELIEF_SUNKEN: indicates how - * stuff to left of trajectory looks - * relative to stuff on right. */ -{ - XPoint poly[4], b1, b2, newB1, newB2; - XPoint perp, c, shift1, shift2; /* Used for handling parallel lines. */ - register XPoint *p1Ptr, *p2Ptr; - TkBorder *borderPtr = (TkBorder *) border; - GC gc; - int i, lightOnLeft, dx, dy, parallel, pointsSeen; - Display *display = Tk_Display(tkwin); - - if (borderPtr->lightGC == None) { - TkpGetShadows(borderPtr, tkwin); - } - - /* - * Handle grooves and ridges with recursive calls. - */ - - if ((leftRelief == TK_RELIEF_GROOVE) || (leftRelief == TK_RELIEF_RIDGE)) { - int halfWidth; - - halfWidth = borderWidth/2; - Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints, - halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED - : TK_RELIEF_SUNKEN); - Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints, - -halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN - : TK_RELIEF_RAISED); - return; - } - - /* - * If the polygon is already closed, drop the last point from it - * (we'll close it automatically). - */ - - p1Ptr = &pointPtr[numPoints-1]; - p2Ptr = &pointPtr[0]; - if ((p1Ptr->x == p2Ptr->x) && (p1Ptr->y == p2Ptr->y)) { - numPoints--; - } - - /* - * The loop below is executed once for each vertex in the polgon. - * At the beginning of each iteration things look like this: - * - * poly[1] / - * * / - * | / - * b1 * poly[0] (pointPtr[i-1]) - * | | - * | | - * | | - * | | - * | | - * | | *p1Ptr *p2Ptr - * b2 *--------------------* - * | - * | - * x------------------------- - * - * The job of this iteration is to do the following: - * (a) Compute x (the border corner corresponding to - * pointPtr[i]) and put it in poly[2]. As part of - * this, compute a new b1 and b2 value for the next - * side of the polygon. - * (b) Put pointPtr[i] into poly[3]. - * (c) Draw the polygon given by poly[0..3]. - * (d) Advance poly[0], poly[1], b1, and b2 for the - * next side of the polygon. - */ - - /* - * The above situation doesn't first come into existence until - * two points have been processed; the first two points are - * used to "prime the pump", so some parts of the processing - * are ommitted for these points. The variable "pointsSeen" - * keeps track of the priming process; it has to be separate - * from i in order to be able to ignore duplicate points in the - * polygon. - */ - - pointsSeen = 0; - for (i = -2, p1Ptr = &pointPtr[numPoints-2], p2Ptr = p1Ptr+1; - i < numPoints; i++, p1Ptr = p2Ptr, p2Ptr++) { - if ((i == -1) || (i == numPoints-1)) { - p2Ptr = pointPtr; - } - if ((p2Ptr->x == p1Ptr->x) && (p2Ptr->y == p1Ptr->y)) { - /* - * Ignore duplicate points (they'd cause core dumps in - * ShiftLine calls below). - */ - continue; - } - ShiftLine(p1Ptr, p2Ptr, borderWidth, &newB1); - newB2.x = newB1.x + (p2Ptr->x - p1Ptr->x); - newB2.y = newB1.y + (p2Ptr->y - p1Ptr->y); - poly[3] = *p1Ptr; - parallel = 0; - if (pointsSeen >= 1) { - parallel = Intersect(&newB1, &newB2, &b1, &b2, &poly[2]); - - /* - * If two consecutive segments of the polygon are parallel, - * then things get more complex. Consider the following - * diagram: - * - * poly[1] - * *----b1-----------b2------a - * \ - * \ - * *---------*----------* b - * poly[0] *p2Ptr *p1Ptr / - * / - * --*--------*----c - * newB1 newB2 - * - * Instead of using x and *p1Ptr for poly[2] and poly[3], as - * in the original diagram, use a and b as above. Then instead - * of using x and *p1Ptr for the new poly[0] and poly[1], use - * b and c as above. - * - * Do the computation in three stages: - * 1. Compute a point "perp" such that the line p1Ptr-perp - * is perpendicular to p1Ptr-p2Ptr. - * 2. Compute the points a and c by intersecting the lines - * b1-b2 and newB1-newB2 with p1Ptr-perp. - * 3. Compute b by shifting p1Ptr-perp to the right and - * intersecting it with p1Ptr-p2Ptr. - */ - - if (parallel) { - perp.x = p1Ptr->x + (p2Ptr->y - p1Ptr->y); - perp.y = p1Ptr->y - (p2Ptr->x - p1Ptr->x); - (void) Intersect(p1Ptr, &perp, &b1, &b2, &poly[2]); - (void) Intersect(p1Ptr, &perp, &newB1, &newB2, &c); - ShiftLine(p1Ptr, &perp, borderWidth, &shift1); - shift2.x = shift1.x + (perp.x - p1Ptr->x); - shift2.y = shift1.y + (perp.y - p1Ptr->y); - (void) Intersect(p1Ptr, p2Ptr, &shift1, &shift2, &poly[3]); - } - } - if (pointsSeen >= 2) { - dx = poly[3].x - poly[0].x; - dy = poly[3].y - poly[0].y; - if (dx > 0) { - lightOnLeft = (dy <= dx); - } else { - lightOnLeft = (dy < dx); - } - if (lightOnLeft ^ (leftRelief == TK_RELIEF_RAISED)) { - gc = borderPtr->lightGC; - } else { - gc = borderPtr->darkGC; - } - XFillPolygon(display, drawable, gc, poly, 4, Convex, - CoordModeOrigin); - } - b1.x = newB1.x; - b1.y = newB1.y; - b2.x = newB2.x; - b2.y = newB2.y; - poly[0].x = poly[3].x; - poly[0].y = poly[3].y; - if (parallel) { - poly[1].x = c.x; - poly[1].y = c.y; - } else if (pointsSeen >= 1) { - poly[1].x = poly[2].x; - poly[1].y = poly[2].y; - } - pointsSeen++; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_Fill3DRectangle -- - * - * Fill a rectangular area, supplying a 3D border if desired. - * - * Results: - * None. - * - * Side effects: - * Information gets drawn on the screen. - * - *---------------------------------------------------------------------- - */ - -void -Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width, - height, borderWidth, relief) - Tk_Window tkwin; /* Window for which border was allocated. */ - Drawable drawable; /* X window or pixmap in which to draw. */ - Tk_3DBorder border; /* Token for border to draw. */ - int x, y, width, height; /* Outside area of rectangular region. */ - int borderWidth; /* Desired width for border, in - * pixels. Border will be *inside* region. */ - int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, - * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ -{ - register TkBorder *borderPtr = (TkBorder *) border; - int doubleBorder; - - /* - * This code is slightly tricky because it only draws the background - * in areas not covered by the 3D border. This avoids flashing - * effects on the screen for the border region. - */ - - if (relief == TK_RELIEF_FLAT) { - borderWidth = 0; - } - doubleBorder = 2*borderWidth; - - if ((width > doubleBorder) && (height > doubleBorder)) { - XFillRectangle(Tk_Display(tkwin), drawable, borderPtr->bgGC, - x + borderWidth, y + borderWidth, - (unsigned int) (width - doubleBorder), - (unsigned int) (height - doubleBorder)); - } - if (borderWidth) { - Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, - height, borderWidth, relief); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_Fill3DPolygon -- - * - * Fill a polygonal area, supplying a 3D border if desired. - * - * Results: - * None. - * - * Side effects: - * Information gets drawn on the screen. - * - *---------------------------------------------------------------------- - */ - -void -Tk_Fill3DPolygon(tkwin, drawable, border, pointPtr, numPoints, - borderWidth, leftRelief) - Tk_Window tkwin; /* Window for which border was allocated. */ - Drawable drawable; /* X window or pixmap in which to draw. */ - Tk_3DBorder border; /* Token for border to draw. */ - XPoint *pointPtr; /* Array of points describing - * polygon. All points must be - * absolute (CoordModeOrigin). */ - int numPoints; /* Number of points at *pointPtr. */ - int borderWidth; /* Width of border, measured in - * pixels to the left of the polygon's - * trajectory. May be negative. */ - int leftRelief; /* Indicates 3D effect of left side of - * trajectory relative to right: - * TK_RELIEF_FLAT, TK_RELIEF_RAISED, - * or TK_RELIEF_SUNKEN. */ -{ - register TkBorder *borderPtr = (TkBorder *) border; - - XFillPolygon(Tk_Display(tkwin), drawable, borderPtr->bgGC, - pointPtr, numPoints, Complex, CoordModeOrigin); - if (leftRelief != TK_RELIEF_FLAT) { - Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints, - borderWidth, leftRelief); - } -} - -/* - *-------------------------------------------------------------- - * - * BorderInit -- - * - * Initialize the structures used for border management. - * - * Results: - * None. - * - * Side effects: - * Read the code. - * - *------------------------------------------------------------- - */ - -static void -BorderInit() -{ - initialized = 1; - Tcl_InitHashTable(&borderTable, sizeof(BorderKey)/sizeof(int)); -} - -/* - *-------------------------------------------------------------- - * - * ShiftLine -- - * - * Given two points on a line, compute a point on a - * new line that is parallel to the given line and - * a given distance away from it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -ShiftLine(p1Ptr, p2Ptr, distance, p3Ptr) - XPoint *p1Ptr; /* First point on line. */ - XPoint *p2Ptr; /* Second point on line. */ - int distance; /* New line is to be this many - * units to the left of original - * line, when looking from p1 to - * p2. May be negative. */ - XPoint *p3Ptr; /* Store coords of point on new - * line here. */ -{ - int dx, dy, dxNeg, dyNeg; - - /* - * The table below is used for a quick approximation in - * computing the new point. An index into the table - * is 128 times the slope of the original line (the slope - * must always be between 0 and 1). The value of the table - * entry is 128 times the amount to displace the new line - * in y for each unit of perpendicular distance. In other - * words, the table maps from the tangent of an angle to - * the inverse of its cosine. If the slope of the original - * line is greater than 1, then the displacement is done in - * x rather than in y. - */ - - static int shiftTable[129]; - - /* - * Initialize the table if this is the first time it is - * used. - */ - - if (shiftTable[0] == 0) { - int i; - double tangent, cosine; - - for (i = 0; i <= 128; i++) { - tangent = i/128.0; - cosine = 128/cos(atan(tangent)) + .5; - shiftTable[i] = (int) cosine; - } - } - - *p3Ptr = *p1Ptr; - dx = p2Ptr->x - p1Ptr->x; - dy = p2Ptr->y - p1Ptr->y; - if (dy < 0) { - dyNeg = 1; - dy = -dy; - } else { - dyNeg = 0; - } - if (dx < 0) { - dxNeg = 1; - dx = -dx; - } else { - dxNeg = 0; - } - if (dy <= dx) { - dy = ((distance * shiftTable[(dy<<7)/dx]) + 64) >> 7; - if (!dxNeg) { - dy = -dy; - } - p3Ptr->y += dy; - } else { - dx = ((distance * shiftTable[(dx<<7)/dy]) + 64) >> 7; - if (dyNeg) { - dx = -dx; - } - p3Ptr->x += dx; - } -} - -/* - *-------------------------------------------------------------- - * - * Intersect -- - * - * Find the intersection point between two lines. - * - * Results: - * Under normal conditions 0 is returned and the point - * at *iPtr is filled in with the intersection between - * the two lines. If the two lines are parallel, then - * -1 is returned and *iPtr isn't modified. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -Intersect(a1Ptr, a2Ptr, b1Ptr, b2Ptr, iPtr) - XPoint *a1Ptr; /* First point of first line. */ - XPoint *a2Ptr; /* Second point of first line. */ - XPoint *b1Ptr; /* First point of second line. */ - XPoint *b2Ptr; /* Second point of second line. */ - XPoint *iPtr; /* Filled in with intersection point. */ -{ - int dxadyb, dxbdya, dxadxb, dyadyb, p, q; - - /* - * The code below is just a straightforward manipulation of two - * equations of the form y = (x-x1)*(y2-y1)/(x2-x1) + y1 to solve - * for the x-coordinate of intersection, then the y-coordinate. - */ - - dxadyb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->y - b1Ptr->y); - dxbdya = (b2Ptr->x - b1Ptr->x)*(a2Ptr->y - a1Ptr->y); - dxadxb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->x - b1Ptr->x); - dyadyb = (a2Ptr->y - a1Ptr->y)*(b2Ptr->y - b1Ptr->y); - - if (dxadyb == dxbdya) { - return -1; - } - p = (a1Ptr->x*dxbdya - b1Ptr->x*dxadyb + (b1Ptr->y - a1Ptr->y)*dxadxb); - q = dxbdya - dxadyb; - if (q < 0) { - p = -p; - q = -q; - } - if (p < 0) { - iPtr->x = - ((-p + q/2)/q); - } else { - iPtr->x = (p + q/2)/q; - } - p = (a1Ptr->y*dxadyb - b1Ptr->y*dxbdya + (b1Ptr->x - a1Ptr->x)*dyadyb); - q = dxadyb - dxbdya; - if (q < 0) { - p = -p; - q = -q; - } - if (p < 0) { - iPtr->y = - ((-p + q/2)/q); - } else { - iPtr->y = (p + q/2)/q; - } - return 0; -} diff --git a/generic/tk3d.h b/generic/tk3d.h deleted file mode 100644 index 1ec63d0..0000000 --- a/generic/tk3d.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * tk3d.h -- - * - * Declarations of types and functions shared by the 3d border - * module. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tk3d.h,v 1.4 1998/09/14 18:23:03 stanton Exp $ - */ - -#ifndef _TK3D -#define _TK3D - -#include <tkInt.h> - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * One of the following data structures is allocated for - * each 3-D border currently in use. Structures of this - * type are indexed by borderTable, so that a single - * structure can be shared for several uses. - */ - -typedef struct { - Screen *screen; /* Screen on which the border will be used. */ - Visual *visual; /* Visual for all windows and pixmaps using - * the border. */ - int depth; /* Number of bits per pixel of drawables where - * the border will be used. */ - Colormap colormap; /* Colormap out of which pixels are - * allocated. */ - int refCount; /* Number of different users of - * this border. */ - XColor *bgColorPtr; /* Background color (intensity - * between lightColorPtr and - * darkColorPtr). */ - XColor *darkColorPtr; /* Color for darker areas (must free when - * deleting structure). NULL means shadows - * haven't been allocated yet.*/ - XColor *lightColorPtr; /* Color used for lighter areas of border - * (must free this when deleting structure). - * NULL means shadows haven't been allocated - * yet. */ - Pixmap shadow; /* Stipple pattern to use for drawing - * shadows areas. Used for displays with - * <= 64 colors or where colormap has filled - * up. */ - GC bgGC; /* Used (if necessary) to draw areas in - * the background color. */ - GC darkGC; /* Used to draw darker parts of the - * border. None means the shadow colors - * haven't been allocated yet.*/ - GC lightGC; /* Used to draw lighter parts of - * the border. None means the shadow colors - * haven't been allocated yet. */ - Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in - * order to delete structure). */ -} TkBorder; - - -/* - * Maximum intensity for a color: - */ - -#define MAX_INTENSITY 65535 - -/* - * Declarations for platform specific interfaces used by this module. - */ - -EXTERN TkBorder * TkpGetBorder _ANSI_ARGS_((void)); -EXTERN void TkpGetShadows _ANSI_ARGS_((TkBorder *borderPtr, - Tk_Window tkwin)); -EXTERN void TkpFreeBorder _ANSI_ARGS_((TkBorder *borderPtr)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TK3D */ diff --git a/generic/tkArgv.c b/generic/tkArgv.c deleted file mode 100644 index 8d5d661..0000000 --- a/generic/tkArgv.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * tkArgv.c -- - * - * This file contains a procedure that handles table-based - * argv-argc parsing. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkArgv.c,v 1.2 1998/09/14 18:23:03 stanton Exp $ - */ - -#include "tkPort.h" -#include "tk.h" - -/* - * Default table of argument descriptors. These are normally available - * in every application. - */ - -static Tk_ArgvInfo defaultTable[] = { - {"-help", TK_ARGV_HELP, (char *) NULL, (char *) NULL, - "Print summary of command-line options and abort"}, - {NULL, TK_ARGV_END, (char *) NULL, (char *) NULL, - (char *) NULL} -}; - -/* - * Forward declarations for procedures defined in this file: - */ - -static void PrintUsage _ANSI_ARGS_((Tcl_Interp *interp, - Tk_ArgvInfo *argTable, int flags)); - -/* - *---------------------------------------------------------------------- - * - * Tk_ParseArgv -- - * - * Process an argv array according to a table of expected - * command-line options. See the manual page for more details. - * - * Results: - * The return value is a standard Tcl return value. If an - * error occurs then an error message is left in interp->result. - * Under normal conditions, both *argcPtr and *argv are modified - * to return the arguments that couldn't be processed here (they - * didn't match the option table, or followed an TK_ARGV_REST - * argument). - * - * Side effects: - * Variables may be modified, resources may be entered for tkwin, - * or procedures may be called. It all depends on the arguments - * and their entries in argTable. See the user documentation - * for details. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags) - Tcl_Interp *interp; /* Place to store error message. */ - Tk_Window tkwin; /* Window to use for setting Tk options. - * NULL means ignore Tk option specs. */ - int *argcPtr; /* Number of arguments in argv. Modified - * to hold # args left in argv at end. */ - char **argv; /* Array of arguments. Modified to hold - * those that couldn't be processed here. */ - Tk_ArgvInfo *argTable; /* Array of option descriptions */ - int flags; /* Or'ed combination of various flag bits, - * such as TK_ARGV_NO_DEFAULTS. */ -{ - register Tk_ArgvInfo *infoPtr; - /* Pointer to the current entry in the - * table of argument descriptions. */ - Tk_ArgvInfo *matchPtr; /* Descriptor that matches current argument. */ - char *curArg; /* Current argument */ - register char c; /* Second character of current arg (used for - * quick check for matching; use 2nd char. - * because first char. will almost always - * be '-'). */ - int srcIndex; /* Location from which to read next argument - * from argv. */ - int dstIndex; /* Index into argv to which next unused - * argument should be copied (never greater - * than srcIndex). */ - int argc; /* # arguments in argv still to process. */ - size_t length; /* Number of characters in current argument. */ - int i; - - if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) { - srcIndex = dstIndex = 0; - argc = *argcPtr; - } else { - srcIndex = dstIndex = 1; - argc = *argcPtr-1; - } - - while (argc > 0) { - curArg = argv[srcIndex]; - srcIndex++; - argc--; - length = strlen(curArg); - if (length > 0) { - c = curArg[1]; - } else { - c = 0; - } - - /* - * Loop throught the argument descriptors searching for one with - * the matching key string. If found, leave a pointer to it in - * matchPtr. - */ - - matchPtr = NULL; - for (i = 0; i < 2; i++) { - if (i == 0) { - infoPtr = argTable; - } else { - infoPtr = defaultTable; - } - for (; (infoPtr != NULL) && (infoPtr->type != TK_ARGV_END); - infoPtr++) { - if (infoPtr->key == NULL) { - continue; - } - if ((infoPtr->key[1] != c) - || (strncmp(infoPtr->key, curArg, length) != 0)) { - continue; - } - if ((tkwin == NULL) - && ((infoPtr->type == TK_ARGV_CONST_OPTION) - || (infoPtr->type == TK_ARGV_OPTION_VALUE) - || (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) { - continue; - } - if (infoPtr->key[length] == 0) { - matchPtr = infoPtr; - goto gotMatch; - } - if (flags & TK_ARGV_NO_ABBREV) { - continue; - } - if (matchPtr != NULL) { - Tcl_AppendResult(interp, "ambiguous option \"", curArg, - "\"", (char *) NULL); - return TCL_ERROR; - } - matchPtr = infoPtr; - } - } - if (matchPtr == NULL) { - - /* - * Unrecognized argument. Just copy it down, unless the caller - * prefers an error to be registered. - */ - - if (flags & TK_ARGV_NO_LEFTOVERS) { - Tcl_AppendResult(interp, "unrecognized argument \"", - curArg, "\"", (char *) NULL); - return TCL_ERROR; - } - argv[dstIndex] = curArg; - dstIndex++; - continue; - } - - /* - * Take the appropriate action based on the option type - */ - - gotMatch: - infoPtr = matchPtr; - switch (infoPtr->type) { - case TK_ARGV_CONSTANT: - *((int *) infoPtr->dst) = (int) infoPtr->src; - break; - case TK_ARGV_INT: - if (argc == 0) { - goto missingArg; - } else { - char *endPtr; - - *((int *) infoPtr->dst) = - strtol(argv[srcIndex], &endPtr, 0); - if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { - Tcl_AppendResult(interp, "expected integer argument ", - "for \"", infoPtr->key, "\" but got \"", - argv[srcIndex], "\"", (char *) NULL); - return TCL_ERROR; - } - srcIndex++; - argc--; - } - break; - case TK_ARGV_STRING: - if (argc == 0) { - goto missingArg; - } else { - *((char **)infoPtr->dst) = argv[srcIndex]; - srcIndex++; - argc--; - } - break; - case TK_ARGV_UID: - if (argc == 0) { - goto missingArg; - } else { - *((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]); - srcIndex++; - argc--; - } - break; - case TK_ARGV_REST: - *((int *) infoPtr->dst) = dstIndex; - goto argsDone; - case TK_ARGV_FLOAT: - if (argc == 0) { - goto missingArg; - } else { - char *endPtr; - - *((double *) infoPtr->dst) = - strtod(argv[srcIndex], &endPtr); - if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) { - Tcl_AppendResult(interp, "expected floating-point ", - "argument for \"", infoPtr->key, - "\" but got \"", argv[srcIndex], "\"", - (char *) NULL); - return TCL_ERROR; - } - srcIndex++; - argc--; - } - break; - case TK_ARGV_FUNC: { - typedef int (ArgvFunc)_ANSI_ARGS_((char *, char *, char *)); - ArgvFunc *handlerProc; - - handlerProc = (ArgvFunc *) infoPtr->src; - if ((*handlerProc)(infoPtr->dst, infoPtr->key, - argv[srcIndex])) { - srcIndex += 1; - argc -= 1; - } - break; - } - case TK_ARGV_GENFUNC: { - typedef int (ArgvGenFunc)_ANSI_ARGS_((char *, Tcl_Interp *, - char *, int, char **)); - ArgvGenFunc *handlerProc; - - handlerProc = (ArgvGenFunc *) infoPtr->src; - argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key, - argc, argv+srcIndex); - if (argc < 0) { - return TCL_ERROR; - } - break; - } - case TK_ARGV_HELP: - PrintUsage (interp, argTable, flags); - return TCL_ERROR; - case TK_ARGV_CONST_OPTION: - Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src, - TK_INTERACTIVE_PRIO); - break; - case TK_ARGV_OPTION_VALUE: - if (argc < 1) { - goto missingArg; - } - Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex], - TK_INTERACTIVE_PRIO); - srcIndex++; - argc--; - break; - case TK_ARGV_OPTION_NAME_VALUE: - if (argc < 2) { - Tcl_AppendResult(interp, "\"", curArg, - "\" option requires two following arguments", - (char *) NULL); - return TCL_ERROR; - } - Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1], - TK_INTERACTIVE_PRIO); - srcIndex += 2; - argc -= 2; - break; - default: - sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo", - infoPtr->type); - return TCL_ERROR; - } - } - - /* - * If we broke out of the loop because of an OPT_REST argument, - * copy the remaining arguments down. - */ - - argsDone: - while (argc) { - argv[dstIndex] = argv[srcIndex]; - srcIndex++; - dstIndex++; - argc--; - } - argv[dstIndex] = (char *) NULL; - *argcPtr = dstIndex; - return TCL_OK; - - missingArg: - Tcl_AppendResult(interp, "\"", curArg, - "\" option requires an additional argument", (char *) NULL); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * PrintUsage -- - * - * Generate a help string describing command-line options. - * - * Results: - * Interp->result will be modified to hold a help string - * describing all the options in argTable, plus all those - * in the default table unless TK_ARGV_NO_DEFAULTS is - * specified in flags. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -PrintUsage(interp, argTable, flags) - Tcl_Interp *interp; /* Place information in this interp's - * result area. */ - Tk_ArgvInfo *argTable; /* Array of command-specific argument - * descriptions. */ - int flags; /* If the TK_ARGV_NO_DEFAULTS bit is set - * in this word, then don't generate - * information for default options. */ -{ - register Tk_ArgvInfo *infoPtr; - int width, i, numSpaces; -#define NUM_SPACES 20 - static char spaces[] = " "; - char tmp[30]; - - /* - * First, compute the width of the widest option key, so that we - * can make everything line up. - */ - - width = 4; - for (i = 0; i < 2; i++) { - for (infoPtr = i ? defaultTable : argTable; - infoPtr->type != TK_ARGV_END; infoPtr++) { - int length; - if (infoPtr->key == NULL) { - continue; - } - length = strlen(infoPtr->key); - if (length > width) { - width = length; - } - } - } - - Tcl_AppendResult(interp, "Command-specific options:", (char *) NULL); - for (i = 0; ; i++) { - for (infoPtr = i ? defaultTable : argTable; - infoPtr->type != TK_ARGV_END; infoPtr++) { - if ((infoPtr->type == TK_ARGV_HELP) && (infoPtr->key == NULL)) { - Tcl_AppendResult(interp, "\n", infoPtr->help, (char *) NULL); - continue; - } - Tcl_AppendResult(interp, "\n ", infoPtr->key, ":", (char *) NULL); - numSpaces = width + 1 - strlen(infoPtr->key); - while (numSpaces > 0) { - if (numSpaces >= NUM_SPACES) { - Tcl_AppendResult(interp, spaces, (char *) NULL); - } else { - Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces, - (char *) NULL); - } - numSpaces -= NUM_SPACES; - } - Tcl_AppendResult(interp, infoPtr->help, (char *) NULL); - switch (infoPtr->type) { - case TK_ARGV_INT: { - sprintf(tmp, "%d", *((int *) infoPtr->dst)); - Tcl_AppendResult(interp, "\n\t\tDefault value: ", - tmp, (char *) NULL); - break; - } - case TK_ARGV_FLOAT: { - sprintf(tmp, "%g", *((double *) infoPtr->dst)); - Tcl_AppendResult(interp, "\n\t\tDefault value: ", - tmp, (char *) NULL); - break; - } - case TK_ARGV_STRING: { - char *string; - - string = *((char **) infoPtr->dst); - if (string != NULL) { - Tcl_AppendResult(interp, "\n\t\tDefault value: \"", - string, "\"", (char *) NULL); - } - break; - } - default: { - break; - } - } - } - - if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) { - break; - } - Tcl_AppendResult(interp, "\nGeneric options for all commands:", - (char *) NULL); - } -} diff --git a/generic/tkAtom.c b/generic/tkAtom.c deleted file mode 100644 index fba9fb8..0000000 --- a/generic/tkAtom.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * tkAtom.c -- - * - * This file manages a cache of X Atoms in order to avoid - * interactions with the X server. It's much like the Xmu - * routines, except it has a cleaner interface (caller - * doesn't have to provide permanent storage for atom names, - * for example). - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkAtom.c,v 1.2 1998/09/14 18:23:03 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * The following are a list of the predefined atom strings. - * They should match those found in xatom.h - */ - -static char * atomNameArray[] = { - "PRIMARY", "SECONDARY", "ARC", - "ATOM", "BITMAP", "CARDINAL", - "COLORMAP", "CURSOR", "CUT_BUFFER0", - "CUT_BUFFER1", "CUT_BUFFER2", "CUT_BUFFER3", - "CUT_BUFFER4", "CUT_BUFFER5", "CUT_BUFFER6", - "CUT_BUFFER7", "DRAWABLE", "FONT", - "INTEGER", "PIXMAP", "POINT", - "RECTANGLE", "RESOURCE_MANAGER", "RGB_COLOR_MAP", - "RGB_BEST_MAP", "RGB_BLUE_MAP", "RGB_DEFAULT_MAP", - "RGB_GRAY_MAP", "RGB_GREEN_MAP", "RGB_RED_MAP", - "STRING", "VISUALID", "WINDOW", - "WM_COMMAND", "WM_HINTS", "WM_CLIENT_MACHINE", - "WM_ICON_NAME", "WM_ICON_SIZE", "WM_NAME", - "WM_NORMAL_HINTS", "WM_SIZE_HINTS", "WM_ZOOM_HINTS", - "MIN_SPACE", "NORM_SPACE", "MAX_SPACE", - "END_SPACE", "SUPERSCRIPT_X", "SUPERSCRIPT_Y", - "SUBSCRIPT_X", "SUBSCRIPT_Y", "UNDERLINE_POSITION", - "UNDERLINE_THICKNESS", "STRIKEOUT_ASCENT", "STRIKEOUT_DESCENT", - "ITALIC_ANGLE", "X_HEIGHT", "QUAD_WIDTH", - "WEIGHT", "POINT_SIZE", "RESOLUTION", - "COPYRIGHT", "NOTICE", "FONT_NAME", - "FAMILY_NAME", "FULL_NAME", "CAP_HEIGHT", - "WM_CLASS", "WM_TRANSIENT_FOR", - (char *) NULL -}; - -/* - * Forward references to procedures defined in this file: - */ - -static void AtomInit _ANSI_ARGS_((TkDisplay *dispPtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_InternAtom -- - * - * Given a string, produce the equivalent X atom. This - * procedure is equivalent to XInternAtom, except that it - * keeps a local cache of atoms. Once a name is known, - * the server need not be contacted again for that name. - * - * Results: - * The return value is the Atom corresponding to name. - * - * Side effects: - * A new entry may be added to the local atom cache. - * - *-------------------------------------------------------------- - */ - -Atom -Tk_InternAtom(tkwin, name) - Tk_Window tkwin; /* Window token; map name to atom - * for this window's display. */ - char *name; /* Name to turn into atom. */ -{ - register TkDisplay *dispPtr; - register Tcl_HashEntry *hPtr; - int new; - - dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!dispPtr->atomInit) { - AtomInit(dispPtr); - } - - hPtr = Tcl_CreateHashEntry(&dispPtr->nameTable, name, &new); - if (new) { - Tcl_HashEntry *hPtr2; - Atom atom; - - atom = XInternAtom(dispPtr->display, name, False); - Tcl_SetHashValue(hPtr, atom); - hPtr2 = Tcl_CreateHashEntry(&dispPtr->atomTable, (char *) atom, - &new); - Tcl_SetHashValue(hPtr2, Tcl_GetHashKey(&dispPtr->nameTable, hPtr)); - } - return (Atom) Tcl_GetHashValue(hPtr); -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetAtomName -- - * - * This procedure is equivalent to XGetAtomName except that - * it uses the local atom cache to avoid contacting the - * server. - * - * Results: - * The return value is a character string corresponding to - * the atom given by "atom". This string's storage space - * is static: it need not be freed by the caller, and should - * not be modified by the caller. If "atom" doesn't exist - * on tkwin's display, then the string "?bad atom?" is returned. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_GetAtomName(tkwin, atom) - Tk_Window tkwin; /* Window token; map atom to name - * relative to this window's - * display. */ - Atom atom; /* Atom whose name is wanted. */ -{ - register TkDisplay *dispPtr; - register Tcl_HashEntry *hPtr; - - dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!dispPtr->atomInit) { - AtomInit(dispPtr); - } - - hPtr = Tcl_FindHashEntry(&dispPtr->atomTable, (char *) atom); - if (hPtr == NULL) { - char *name; - Tk_ErrorHandler handler; - int new, mustFree; - - handler= Tk_CreateErrorHandler(dispPtr->display, BadAtom, - -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); - name = XGetAtomName(dispPtr->display, atom); - mustFree = 1; - if (name == NULL) { - name = "?bad atom?"; - mustFree = 0; - } - Tk_DeleteErrorHandler(handler); - hPtr = Tcl_CreateHashEntry(&dispPtr->nameTable, (char *) name, - &new); - Tcl_SetHashValue(hPtr, atom); - if (mustFree) { - XFree(name); - } - name = Tcl_GetHashKey(&dispPtr->nameTable, hPtr); - hPtr = Tcl_CreateHashEntry(&dispPtr->atomTable, (char *) atom, - &new); - Tcl_SetHashValue(hPtr, name); - } - return (char *) Tcl_GetHashValue(hPtr); -} - -/* - *-------------------------------------------------------------- - * - * AtomInit -- - * - * Initialize atom-related information for a display. - * - * Results: - * None. - * - * Side effects: - * Tables get initialized, etc. etc.. - * - *-------------------------------------------------------------- - */ - -static void -AtomInit(dispPtr) - register TkDisplay *dispPtr; /* Display to initialize. */ -{ - Tcl_HashEntry *hPtr; - Atom atom; - - dispPtr->atomInit = 1; - Tcl_InitHashTable(&dispPtr->nameTable, TCL_STRING_KEYS); - Tcl_InitHashTable(&dispPtr->atomTable, TCL_ONE_WORD_KEYS); - - for (atom = 1; atom <= XA_LAST_PREDEFINED; atom++) { - hPtr = Tcl_FindHashEntry(&dispPtr->atomTable, (char *) atom); - if (hPtr == NULL) { - char *name; - int new; - - name = atomNameArray[atom - 1]; - hPtr = Tcl_CreateHashEntry(&dispPtr->nameTable, (char *) name, - &new); - Tcl_SetHashValue(hPtr, atom); - name = Tcl_GetHashKey(&dispPtr->nameTable, hPtr); - hPtr = Tcl_CreateHashEntry(&dispPtr->atomTable, (char *) atom, - &new); - Tcl_SetHashValue(hPtr, name); - } - } -} diff --git a/generic/tkBind.c b/generic/tkBind.c deleted file mode 100644 index 6fcafd2..0000000 --- a/generic/tkBind.c +++ /dev/null @@ -1,4533 +0,0 @@ -/* - * tkBind.c -- - * - * This file provides procedures that associate Tcl commands - * with X events or sequences of X events. - * - * Copyright (c) 1989-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkBind.c,v 1.3 1998/09/14 18:23:03 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * File structure: - * - * Structure definitions and static variables. - * - * Init/Free this package. - * - * Tcl "bind" command (actually located in tkCmds.c). - * "bind" command implementation. - * "bind" implementation helpers. - * - * Tcl "event" command. - * "event" command implementation. - * "event" implementation helpers. - * - * Package-specific common helpers. - * - * Non-package-specific helpers. - */ - - -/* - * The following union is used to hold the detail information from an - * XEvent (including Tk's XVirtualEvent extension). - */ -typedef union { - KeySym keySym; /* KeySym that corresponds to xkey.keycode. */ - int button; /* Button that was pressed (xbutton.button). */ - Tk_Uid name; /* Tk_Uid of virtual event. */ - ClientData clientData; /* Used when type of Detail is unknown, and to - * ensure that all bytes of Detail are initialized - * when this structure is used in a hash key. */ -} Detail; - -/* - * The structure below represents a binding table. A binding table - * represents a domain in which event bindings may occur. It includes - * a space of objects relative to which events occur (usually windows, - * but not always), a history of recent events in the domain, and - * a set of mappings that associate particular Tcl commands with sequences - * of events in the domain. Multiple binding tables may exist at once, - * either because there are multiple applications open, or because there - * are multiple domains within an application with separate event - * bindings for each (for example, each canvas widget has a separate - * binding table for associating events with the items in the canvas). - * - * Note: it is probably a bad idea to reduce EVENT_BUFFER_SIZE much - * below 30. To see this, consider a triple mouse button click while - * the Shift key is down (and auto-repeating). There may be as many - * as 3 auto-repeat events after each mouse button press or release - * (see the first large comment block within Tk_BindEvent for more on - * this), for a total of 20 events to cover the three button presses - * and two intervening releases. If you reduce EVENT_BUFFER_SIZE too - * much, shift multi-clicks will be lost. - * - */ - -#define EVENT_BUFFER_SIZE 30 -typedef struct BindingTable { - XEvent eventRing[EVENT_BUFFER_SIZE];/* Circular queue of recent events - * (higher indices are for more recent - * events). */ - Detail detailRing[EVENT_BUFFER_SIZE];/* "Detail" information (keySym, - * button, Tk_Uid, or 0) for each - * entry in eventRing. */ - int curEvent; /* Index in eventRing of most recent - * event. Newer events have higher - * indices. */ - Tcl_HashTable patternTable; /* Used to map from an event to a - * list of patterns that may match that - * event. Keys are PatternTableKey - * structs, values are (PatSeq *). */ - Tcl_HashTable objectTable; /* Used to map from an object to a - * list of patterns associated with - * that object. Keys are ClientData, - * values are (PatSeq *). */ - Tcl_Interp *interp; /* Interpreter in which commands are - * executed. */ -} BindingTable; - -/* - * The following structure represents virtual event table. A virtual event - * table provides a way to map from platform-specific physical events such - * as button clicks or key presses to virtual events such as <<Paste>>, - * <<Close>>, or <<ScrollWindow>>. - * - * A virtual event is usually never part of the event stream, but instead is - * synthesized inline by matching low-level events. However, a virtual - * event may be generated by platform-specific code or by Tcl scripts. In - * that case, no lookup of the virtual event will need to be done using - * this table, because the virtual event is actually in the event stream. - */ - -typedef struct VirtualEventTable { - Tcl_HashTable patternTable; /* Used to map from a physical event to - * a list of patterns that may match that - * event. Keys are PatternTableKey - * structs, values are (PatSeq *). */ - Tcl_HashTable nameTable; /* Used to map a virtual event name to - * the array of physical events that can - * trigger it. Keys are the Tk_Uid names - * of the virtual events, values are - * PhysicalsOwned structs. */ -} VirtualEventTable; - -/* - * The following structure is used as a key in a patternTable for both - * binding tables and a virtual event tables. - * - * In a binding table, the object field corresponds to the binding tag - * for the widget whose bindings are being accessed. - * - * In a virtual event table, the object field is always NULL. Virtual - * events are a global definiton and are not tied to a particular - * binding tag. - * - * The same key is used for both types of pattern tables so that the - * helper functions that traverse and match patterns will work for both - * binding tables and virtual event tables. - */ -typedef struct PatternTableKey { - ClientData object; /* For binding table, identifies the binding - * tag of the object (or class of objects) - * relative to which the event occurred. - * For virtual event table, always NULL. */ - int type; /* Type of event (from X). */ - Detail detail; /* Additional information, such as keysym, - * button, Tk_Uid, or 0 if nothing - * additional. */ -} PatternTableKey; - -/* - * The following structure defines a pattern, which is matched against X - * events as part of the process of converting X events into Tcl commands. - */ - -typedef struct Pattern { - int eventType; /* Type of X event, e.g. ButtonPress. */ - int needMods; /* Mask of modifiers that must be - * present (0 means no modifiers are - * required). */ - Detail detail; /* Additional information that must - * match event. Normally this is 0, - * meaning no additional information - * must match. For KeyPress and - * KeyRelease events, a keySym may - * be specified to select a - * particular keystroke (0 means any - * keystrokes). For button events, - * specifies a particular button (0 - * means any buttons are OK). For virtual - * events, specifies the Tk_Uid of the - * virtual event name (never 0). */ -} Pattern; - -/* - * The following structure defines a pattern sequence, which consists of one - * or more patterns. In order to trigger, a pattern sequence must match - * the most recent X events (first pattern to most recent event, next - * pattern to next event, and so on). It is used as the hash value in a - * patternTable for both binding tables and virtual event tables. - * - * In a binding table, it is the sequence of physical events that make up - * a binding for an object. - * - * In a virtual event table, it is the sequence of physical events that - * define a virtual event. - * - * The same structure is used for both types of pattern tables so that the - * helper functions that traverse and match patterns will work for both - * binding tables and virtual event tables. - */ - -typedef struct PatSeq { - int numPats; /* Number of patterns in sequence (usually - * 1). */ - TkBindEvalProc *eventProc; /* The procedure that will be invoked on - * the clientData when this pattern sequence - * matches. */ - TkBindFreeProc *freeProc; /* The procedure that will be invoked to - * release the clientData when this pattern - * sequence is freed. */ - ClientData clientData; /* Arbitray data passed to eventProc and - * freeProc when sequence matches. */ - int flags; /* Miscellaneous flag values; see below for - * definitions. */ - int refCount; /* Number of times that this binding is in - * the midst of executing. If greater than 1, - * then a recursive invocation is happening. - * Only when this is zero can the binding - * actually be freed. */ - struct PatSeq *nextSeqPtr; /* Next in list of all pattern sequences - * that have the same initial pattern. NULL - * means end of list. */ - Tcl_HashEntry *hPtr; /* Pointer to hash table entry for the - * initial pattern. This is the head of the - * list of which nextSeqPtr forms a part. */ - struct VirtualOwners *voPtr;/* In a binding table, always NULL. In a - * virtual event table, identifies the array - * of virtual events that can be triggered by - * this event. */ - struct PatSeq *nextObjPtr; /* In a binding table, next in list of all - * pattern sequences for the same object (NULL - * for end of list). Needed to implement - * Tk_DeleteAllBindings. In a virtual event - * table, always NULL. */ - Pattern pats[1]; /* Array of "numPats" patterns. Only one - * element is declared here but in actuality - * enough space will be allocated for "numPats" - * patterns. To match, pats[0] must match - * event n, pats[1] must match event n-1, etc. - */ -} PatSeq; - -/* - * Flag values for PatSeq structures: - * - * PAT_NEARBY 1 means that all of the events matching - * this sequence must occur with nearby X - * and Y mouse coordinates and close in time. - * This is typically used to restrict multiple - * button presses. - * MARKED_DELETED 1 means that this binding has been marked as deleted - * and removed from the binding table, but its memory - * could not be released because it was already queued for - * execution. When the binding is actually about to be - * executed, this flag will be checked and the binding - * skipped if set. - */ - -#define PAT_NEARBY 0x1 -#define MARKED_DELETED 0x2 - -/* - * Constants that define how close together two events must be - * in milliseconds or pixels to meet the PAT_NEARBY constraint: - */ - -#define NEARBY_PIXELS 5 -#define NEARBY_MS 500 - - -/* - * The following structure keeps track of all the virtual events that are - * associated with a particular physical event. It is pointed to by the - * voPtr field in a PatSeq in the patternTable of a virtual event table. - */ - -typedef struct VirtualOwners { - int numOwners; /* Number of virtual events to trigger. */ - Tcl_HashEntry *owners[1]; /* Array of pointers to entries in - * nameTable. Enough space will - * actually be allocated for numOwners - * hash entries. */ -} VirtualOwners; - -/* - * The following structure is used in the nameTable of a virtual event - * table to associate a virtual event with all the physical events that can - * trigger it. - */ -typedef struct PhysicalsOwned { - int numOwned; /* Number of physical events owned. */ - PatSeq *patSeqs[1]; /* Array of pointers to physical event - * patterns. Enough space will actually - * be allocated to hold numOwned. */ -} PhysicalsOwned; - -/* - * One of the following structures exists for each interpreter. This - * structure keeps track of the current display and screen in the - * interpreter, so that a script can be invoked whenever the display/screen - * changes (the script does things like point tkPriv at a display-specific - * structure). - */ - -typedef struct { - TkDisplay *curDispPtr; /* Display for last binding command invoked - * in this application. */ - int curScreenIndex; /* Index of screen for last binding command. */ - int bindingDepth; /* Number of active instances of Tk_BindEvent - * in this application. */ -} ScreenInfo; - -/* - * The following structure is used to keep track of all the C bindings that - * are awaiting invocation and whether the window they refer to has been - * destroyed. If the window is destroyed, then all pending callbacks for - * that window will be cancelled. The Tcl bindings will still all be - * invoked, however. - */ - -typedef struct PendingBinding { - struct PendingBinding *nextPtr; - /* Next in chain of pending bindings, in - * case a recursive binding evaluation is in - * progress. */ - Tk_Window tkwin; /* The window that the following bindings - * depend upon. */ - int deleted; /* Set to non-zero by window cleanup code - * if tkwin is deleted. */ - PatSeq *matchArray[5]; /* Array of pending C bindings. The actual - * size of this depends on how many C bindings - * matched the event passed to Tk_BindEvent. - * THIS FIELD MUST BE THE LAST IN THE - * STRUCTURE. */ -} PendingBinding; - -/* - * The following structure keeps track of all the information local to - * the binding package on a per interpreter basis. - */ - -typedef struct BindInfo { - VirtualEventTable virtualEventTable; - /* The virtual events that exist in this - * interpreter. */ - ScreenInfo screenInfo; /* Keeps track of the current display and - * screen, so it can be restored after - * a binding has executed. */ - PendingBinding *pendingList;/* The list of pending C bindings, kept in - * case a C or Tcl binding causes the target - * window to be deleted. */ -} BindInfo; - -/* - * In X11R4 and earlier versions, XStringToKeysym is ridiculously - * slow. The data structure and hash table below, along with the - * code that uses them, implement a fast mapping from strings to - * keysyms. In X11R5 and later releases XStringToKeysym is plenty - * fast so this stuff isn't needed. The #define REDO_KEYSYM_LOOKUP - * is normally undefined, so that XStringToKeysym gets used. It - * can be set in the Makefile to enable the use of the hash table - * below. - */ - -#ifdef REDO_KEYSYM_LOOKUP -typedef struct { - char *name; /* Name of keysym. */ - KeySym value; /* Numeric identifier for keysym. */ -} KeySymInfo; -static KeySymInfo keyArray[] = { -#ifndef lint -#include "ks_names.h" -#endif - {(char *) NULL, 0} -}; -static Tcl_HashTable keySymTable; /* keyArray hashed by keysym value. */ -static Tcl_HashTable nameTable; /* keyArray hashed by keysym name. */ -#endif /* REDO_KEYSYM_LOOKUP */ - -/* - * Set to non-zero when the package-wide static variables have been - * initialized. - */ - -static int initialized = 0; - -/* - * A hash table is kept to map from the string names of event - * modifiers to information about those modifiers. The structure - * for storing this information, and the hash table built at - * initialization time, are defined below. - */ - -typedef struct { - char *name; /* Name of modifier. */ - int mask; /* Button/modifier mask value, * such as Button1Mask. */ - int flags; /* Various flags; see below for - * definitions. */ -} ModInfo; - -/* - * Flags for ModInfo structures: - * - * DOUBLE - Non-zero means duplicate this event, - * e.g. for double-clicks. - * TRIPLE - Non-zero means triplicate this event, - * e.g. for triple-clicks. - */ - -#define DOUBLE 1 -#define TRIPLE 2 - -/* - * The following special modifier mask bits are defined, to indicate - * logical modifiers such as Meta and Alt that may float among the - * actual modifier bits. - */ - -#define META_MASK (AnyModifier<<1) -#define ALT_MASK (AnyModifier<<2) - -static ModInfo modArray[] = { - {"Control", ControlMask, 0}, - {"Shift", ShiftMask, 0}, - {"Lock", LockMask, 0}, - {"Meta", META_MASK, 0}, - {"M", META_MASK, 0}, - {"Alt", ALT_MASK, 0}, - {"B1", Button1Mask, 0}, - {"Button1", Button1Mask, 0}, - {"B2", Button2Mask, 0}, - {"Button2", Button2Mask, 0}, - {"B3", Button3Mask, 0}, - {"Button3", Button3Mask, 0}, - {"B4", Button4Mask, 0}, - {"Button4", Button4Mask, 0}, - {"B5", Button5Mask, 0}, - {"Button5", Button5Mask, 0}, - {"Mod1", Mod1Mask, 0}, - {"M1", Mod1Mask, 0}, - {"Command", Mod1Mask, 0}, - {"Mod2", Mod2Mask, 0}, - {"M2", Mod2Mask, 0}, - {"Option", Mod2Mask, 0}, - {"Mod3", Mod3Mask, 0}, - {"M3", Mod3Mask, 0}, - {"Mod4", Mod4Mask, 0}, - {"M4", Mod4Mask, 0}, - {"Mod5", Mod5Mask, 0}, - {"M5", Mod5Mask, 0}, - {"Double", 0, DOUBLE}, - {"Triple", 0, TRIPLE}, - {"Any", 0, 0}, /* Ignored: historical relic. */ - {NULL, 0, 0} -}; -static Tcl_HashTable modTable; - -/* - * This module also keeps a hash table mapping from event names - * to information about those events. The structure, an array - * to use to initialize the hash table, and the hash table are - * all defined below. - */ - -typedef struct { - char *name; /* Name of event. */ - int type; /* Event type for X, such as - * ButtonPress. */ - int eventMask; /* Mask bits (for XSelectInput) - * for this event type. */ -} EventInfo; - -/* - * Note: some of the masks below are an OR-ed combination of - * several masks. This is necessary because X doesn't report - * up events unless you also ask for down events. Also, X - * doesn't report button state in motion events unless you've - * asked about button events. - */ - -static EventInfo eventArray[] = { - {"Key", KeyPress, KeyPressMask}, - {"KeyPress", KeyPress, KeyPressMask}, - {"KeyRelease", KeyRelease, KeyPressMask|KeyReleaseMask}, - {"Button", ButtonPress, ButtonPressMask}, - {"ButtonPress", ButtonPress, ButtonPressMask}, - {"ButtonRelease", ButtonRelease, - ButtonPressMask|ButtonReleaseMask}, - {"Motion", MotionNotify, - ButtonPressMask|PointerMotionMask}, - {"Enter", EnterNotify, EnterWindowMask}, - {"Leave", LeaveNotify, LeaveWindowMask}, - {"FocusIn", FocusIn, FocusChangeMask}, - {"FocusOut", FocusOut, FocusChangeMask}, - {"Expose", Expose, ExposureMask}, - {"Visibility", VisibilityNotify, VisibilityChangeMask}, - {"Destroy", DestroyNotify, StructureNotifyMask}, - {"Unmap", UnmapNotify, StructureNotifyMask}, - {"Map", MapNotify, StructureNotifyMask}, - {"Reparent", ReparentNotify, StructureNotifyMask}, - {"Configure", ConfigureNotify, StructureNotifyMask}, - {"Gravity", GravityNotify, StructureNotifyMask}, - {"Circulate", CirculateNotify, StructureNotifyMask}, - {"Property", PropertyNotify, PropertyChangeMask}, - {"Colormap", ColormapNotify, ColormapChangeMask}, - {"Activate", ActivateNotify, ActivateMask}, - {"Deactivate", DeactivateNotify, ActivateMask}, - {(char *) NULL, 0, 0} -}; -static Tcl_HashTable eventTable; - -/* - * The defines and table below are used to classify events into - * various groups. The reason for this is that logically identical - * fields (e.g. "state") appear at different places in different - * types of events. The classification masks can be used to figure - * out quickly where to extract information from events. - */ - -#define KEY 0x1 -#define BUTTON 0x2 -#define MOTION 0x4 -#define CROSSING 0x8 -#define FOCUS 0x10 -#define EXPOSE 0x20 -#define VISIBILITY 0x40 -#define CREATE 0x80 -#define DESTROY 0x100 -#define UNMAP 0x200 -#define MAP 0x400 -#define REPARENT 0x800 -#define CONFIG 0x1000 -#define GRAVITY 0x2000 -#define CIRC 0x4000 -#define PROP 0x8000 -#define COLORMAP 0x10000 -#define VIRTUAL 0x20000 -#define ACTIVATE 0x40000 - -#define KEY_BUTTON_MOTION_VIRTUAL (KEY|BUTTON|MOTION|VIRTUAL) - -static int flagArray[TK_LASTEVENT] = { - /* Not used */ 0, - /* Not used */ 0, - /* KeyPress */ KEY, - /* KeyRelease */ KEY, - /* ButtonPress */ BUTTON, - /* ButtonRelease */ BUTTON, - /* MotionNotify */ MOTION, - /* EnterNotify */ CROSSING, - /* LeaveNotify */ CROSSING, - /* FocusIn */ FOCUS, - /* FocusOut */ FOCUS, - /* KeymapNotify */ 0, - /* Expose */ EXPOSE, - /* GraphicsExpose */ EXPOSE, - /* NoExpose */ 0, - /* VisibilityNotify */ VISIBILITY, - /* CreateNotify */ CREATE, - /* DestroyNotify */ DESTROY, - /* UnmapNotify */ UNMAP, - /* MapNotify */ MAP, - /* MapRequest */ 0, - /* ReparentNotify */ REPARENT, - /* ConfigureNotify */ CONFIG, - /* ConfigureRequest */ 0, - /* GravityNotify */ GRAVITY, - /* ResizeRequest */ 0, - /* CirculateNotify */ CIRC, - /* CirculateRequest */ 0, - /* PropertyNotify */ PROP, - /* SelectionClear */ 0, - /* SelectionRequest */ 0, - /* SelectionNotify */ 0, - /* ColormapNotify */ COLORMAP, - /* ClientMessage */ 0, - /* MappingNotify */ 0, - /* VirtualEvent */ VIRTUAL, - /* Activate */ ACTIVATE, - /* Deactivate */ ACTIVATE -}; - -/* - * The following tables are used as a two-way map between X's internal - * numeric values for fields in an XEvent and the strings used in Tcl. The - * tables are used both when constructing an XEvent from user input and - * when providing data from an XEvent to the user. - */ - -static TkStateMap notifyMode[] = { - {NotifyNormal, "NotifyNormal"}, - {NotifyGrab, "NotifyGrab"}, - {NotifyUngrab, "NotifyUngrab"}, - {NotifyWhileGrabbed, "NotifyWhileGrabbed"}, - {-1, NULL} -}; - -static TkStateMap notifyDetail[] = { - {NotifyAncestor, "NotifyAncestor"}, - {NotifyVirtual, "NotifyVirtual"}, - {NotifyInferior, "NotifyInferior"}, - {NotifyNonlinear, "NotifyNonlinear"}, - {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"}, - {NotifyPointer, "NotifyPointer"}, - {NotifyPointerRoot, "NotifyPointerRoot"}, - {NotifyDetailNone, "NotifyDetailNone"}, - {-1, NULL} -}; - -static TkStateMap circPlace[] = { - {PlaceOnTop, "PlaceOnTop"}, - {PlaceOnBottom, "PlaceOnBottom"}, - {-1, NULL} -}; - -static TkStateMap visNotify[] = { - {VisibilityUnobscured, "VisibilityUnobscured"}, - {VisibilityPartiallyObscured, "VisibilityPartiallyObscured"}, - {VisibilityFullyObscured, "VisibilityFullyObscured"}, - {-1, NULL} -}; - -/* - * Prototypes for local procedures defined in this file: - */ - -static void ChangeScreen _ANSI_ARGS_((Tcl_Interp *interp, - char *dispName, int screenIndex)); -static int CreateVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, - VirtualEventTable *vetPtr, char *virtString, - char *eventString)); -static int DeleteVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, - VirtualEventTable *vetPtr, char *virtString, - char *eventString)); -static void DeleteVirtualEventTable _ANSI_ARGS_(( - VirtualEventTable *vetPtr)); -static void ExpandPercents _ANSI_ARGS_((TkWindow *winPtr, - char *before, XEvent *eventPtr, KeySym keySym, - Tcl_DString *dsPtr)); -static void FreeTclBinding _ANSI_ARGS_((ClientData clientData)); -static PatSeq * FindSequence _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_HashTable *patternTablePtr, ClientData object, - char *eventString, int create, int allowVirtual, - unsigned long *maskPtr)); -static void GetAllVirtualEvents _ANSI_ARGS_((Tcl_Interp *interp, - VirtualEventTable *vetPtr)); -static char * GetField _ANSI_ARGS_((char *p, char *copy, int size)); -static KeySym GetKeySym _ANSI_ARGS_((TkDisplay *dispPtr, - XEvent *eventPtr)); -static void GetPatternString _ANSI_ARGS_((PatSeq *psPtr, - Tcl_DString *dsPtr)); -static int GetVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, - VirtualEventTable *vetPtr, char *virtString)); -static Tk_Uid GetVirtualEventUid _ANSI_ARGS_((Tcl_Interp *interp, - char *virtString)); -static int HandleEventGenerate _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window main, int argc, char **argv)); -static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); -static void InitVirtualEventTable _ANSI_ARGS_(( - VirtualEventTable *vetPtr)); -static PatSeq * MatchPatterns _ANSI_ARGS_((TkDisplay *dispPtr, - BindingTable *bindPtr, PatSeq *psPtr, - PatSeq *bestPtr, ClientData *objectPtr, - PatSeq **sourcePtrPtr)); -static int ParseEventDescription _ANSI_ARGS_((Tcl_Interp *interp, - char **eventStringPtr, Pattern *patPtr, - unsigned long *eventMaskPtr)); - -/* - * The following define is used as a short circuit for the callback - * procedure to evaluate a TclBinding. The actual evaluation of the - * binding is handled inline, because special things have to be done - * with a Tcl binding before evaluation time. - */ - -#define EvalTclBinding ((TkBindEvalProc *) 1) - - -/* - *--------------------------------------------------------------------------- - * - * TkBindInit -- - * - * This procedure is called when an application is created. It - * initializes all the structures used by bindings and virtual - * events. It must be called before any other functions in this - * file are called. - * - * Results: - * None. - * - * Side effects: - * Memory allocated. - * - *--------------------------------------------------------------------------- - */ - -void -TkBindInit(mainPtr) - TkMainInfo *mainPtr; /* The newly created application. */ -{ - BindInfo *bindInfoPtr; - - if (sizeof(XEvent) < sizeof(XVirtualEvent)) { - panic("TkBindInit: virtual events can't be supported"); - } - - /* - * Initialize the static data structures used by the binding package. - * They are only initialized once, no matter how many interps are - * created. - */ - - if (!initialized) { - Tcl_HashEntry *hPtr; - ModInfo *modPtr; - EventInfo *eiPtr; - int dummy; - -#ifdef REDO_KEYSYM_LOOKUP - KeySymInfo *kPtr; - - Tcl_InitHashTable(&keySymTable, TCL_STRING_KEYS); - Tcl_InitHashTable(&nameTable, TCL_ONE_WORD_KEYS); - for (kPtr = keyArray; kPtr->name != NULL; kPtr++) { - hPtr = Tcl_CreateHashEntry(&keySymTable, kPtr->name, &dummy); - Tcl_SetHashValue(hPtr, kPtr->value); - hPtr = Tcl_CreateHashEntry(&nameTable, (char *) kPtr->value, - &dummy); - Tcl_SetHashValue(hPtr, kPtr->name); - } -#endif /* REDO_KEYSYM_LOOKUP */ - - Tcl_InitHashTable(&modTable, TCL_STRING_KEYS); - for (modPtr = modArray; modPtr->name != NULL; modPtr++) { - hPtr = Tcl_CreateHashEntry(&modTable, modPtr->name, &dummy); - Tcl_SetHashValue(hPtr, modPtr); - } - - Tcl_InitHashTable(&eventTable, TCL_STRING_KEYS); - for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { - hPtr = Tcl_CreateHashEntry(&eventTable, eiPtr->name, &dummy); - Tcl_SetHashValue(hPtr, eiPtr); - } - initialized = 1; - } - - mainPtr->bindingTable = Tk_CreateBindingTable(mainPtr->interp); - - bindInfoPtr = (BindInfo *) ckalloc(sizeof(BindInfo)); - InitVirtualEventTable(&bindInfoPtr->virtualEventTable); - bindInfoPtr->screenInfo.curDispPtr = NULL; - bindInfoPtr->screenInfo.curScreenIndex = -1; - bindInfoPtr->screenInfo.bindingDepth = 0; - bindInfoPtr->pendingList = NULL; - mainPtr->bindInfo = (TkBindInfo) bindInfoPtr; - - TkpInitializeMenuBindings(mainPtr->interp, mainPtr->bindingTable); -} - -/* - *--------------------------------------------------------------------------- - * - * TkBindFree -- - * - * This procedure is called when an application is deleted. It - * deletes all the structures used by bindings and virtual events. - * - * Results: - * None. - * - * Side effects: - * Memory freed. - * - *--------------------------------------------------------------------------- - */ - -void -TkBindFree(mainPtr) - TkMainInfo *mainPtr; /* The newly created application. */ -{ - BindInfo *bindInfoPtr; - - Tk_DeleteBindingTable(mainPtr->bindingTable); - mainPtr->bindingTable = NULL; - - bindInfoPtr = (BindInfo *) mainPtr->bindInfo; - DeleteVirtualEventTable(&bindInfoPtr->virtualEventTable); - mainPtr->bindInfo = NULL; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CreateBindingTable -- - * - * Set up a new domain in which event bindings may be created. - * - * Results: - * The return value is a token for the new table, which must - * be passed to procedures like Tk_CreatBinding. - * - * Side effects: - * Memory is allocated for the new table. - * - *-------------------------------------------------------------- - */ - -Tk_BindingTable -Tk_CreateBindingTable(interp) - Tcl_Interp *interp; /* Interpreter to associate with the binding - * table: commands are executed in this - * interpreter. */ -{ - BindingTable *bindPtr; - int i; - - /* - * Create and initialize a new binding table. - */ - - bindPtr = (BindingTable *) ckalloc(sizeof(BindingTable)); - for (i = 0; i < EVENT_BUFFER_SIZE; i++) { - bindPtr->eventRing[i].type = -1; - } - bindPtr->curEvent = 0; - Tcl_InitHashTable(&bindPtr->patternTable, - sizeof(PatternTableKey)/sizeof(int)); - Tcl_InitHashTable(&bindPtr->objectTable, TCL_ONE_WORD_KEYS); - bindPtr->interp = interp; - return (Tk_BindingTable) bindPtr; -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteBindingTable -- - * - * Destroy a binding table and free up all its memory. - * The caller should not use bindingTable again after - * this procedure returns. - * - * Results: - * None. - * - * Side effects: - * Memory is freed. - * - *-------------------------------------------------------------- - */ - -void -Tk_DeleteBindingTable(bindingTable) - Tk_BindingTable bindingTable; /* Token for the binding table to - * destroy. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr, *nextPtr; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - - /* - * Find and delete all of the patterns associated with the binding - * table. - */ - - for (hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - psPtr != NULL; psPtr = nextPtr) { - nextPtr = psPtr->nextSeqPtr; - psPtr->flags |= MARKED_DELETED; - if (psPtr->refCount == 0) { - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - ckfree((char *) psPtr); - } - } - } - - /* - * Clean up the rest of the information associated with the - * binding table. - */ - - Tcl_DeleteHashTable(&bindPtr->patternTable); - Tcl_DeleteHashTable(&bindPtr->objectTable); - ckfree((char *) bindPtr); -} - -/* - *-------------------------------------------------------------- - * - * Tk_CreateBinding -- - * - * Add a binding to a binding table, so that future calls to - * Tk_BindEvent may execute the command in the binding. - * - * Results: - * The return value is 0 if an error occurred while setting - * up the binding. In this case, an error message will be - * left in interp->result. If all went well then the return - * value is a mask of the event types that must be made - * available to Tk_BindEvent in order to properly detect when - * this binding triggers. This value can be used to determine - * what events to select for in a window, for example. - * - * Side effects: - * An existing binding on the same event sequence may be - * replaced. - * The new binding may cause future calls to Tk_BindEvent to - * behave differently than they did previously. - * - *-------------------------------------------------------------- - */ - -unsigned long -Tk_CreateBinding(interp, bindingTable, object, eventString, command, append) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_BindingTable bindingTable; - /* Table in which to create binding. */ - ClientData object; /* Token for object with which binding is - * associated. */ - char *eventString; /* String describing event sequence that - * triggers binding. */ - char *command; /* Contains Tcl command to execute when - * binding triggers. */ - int append; /* 0 means replace any existing binding for - * eventString; 1 means append to that - * binding. If the existing binding is for a - * callback function and not a Tcl command - * string, the existing binding will always be - * replaced. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr; - unsigned long eventMask; - char *new, *old; - - psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, - 1, 1, &eventMask); - if (psPtr == NULL) { - return 0; - } - if (psPtr->eventProc == NULL) { - int new; - Tcl_HashEntry *hPtr; - - /* - * This pattern sequence was just created. - * Link the pattern into the list associated with the object, so - * that if the object goes away, these bindings will all - * automatically be deleted. - */ - - hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object, - &new); - if (new) { - psPtr->nextObjPtr = NULL; - } else { - psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - } - Tcl_SetHashValue(hPtr, psPtr); - } else if (psPtr->eventProc != EvalTclBinding) { - /* - * Free existing procedural binding. - */ - - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - psPtr->clientData = NULL; - append = 0; - } - - old = (char *) psPtr->clientData; - if ((append != 0) && (old != NULL)) { - int length; - - length = strlen(old) + strlen(command) + 2; - new = (char *) ckalloc((unsigned) length); - sprintf(new, "%s\n%s", old, command); - } else { - new = (char *) ckalloc((unsigned) strlen(command) + 1); - strcpy(new, command); - } - if (old != NULL) { - ckfree(old); - } - psPtr->eventProc = EvalTclBinding; - psPtr->freeProc = FreeTclBinding; - psPtr->clientData = (ClientData) new; - return eventMask; -} - -/* - *--------------------------------------------------------------------------- - * - * TkCreateBindingProcedure -- - * - * Add a C binding to a binding table, so that future calls to - * Tk_BindEvent may callback the procedure in the binding. - * - * Results: - * The return value is 0 if an error occurred while setting - * up the binding. In this case, an error message will be - * left in interp->result. If all went well then the return - * value is a mask of the event types that must be made - * available to Tk_BindEvent in order to properly detect when - * this binding triggers. This value can be used to determine - * what events to select for in a window, for example. - * - * Side effects: - * Any existing binding on the same event sequence will be - * replaced. - * - *--------------------------------------------------------------------------- - */ - -unsigned long -TkCreateBindingProcedure(interp, bindingTable, object, eventString, - eventProc, freeProc, clientData) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_BindingTable bindingTable; - /* Table in which to create binding. */ - ClientData object; /* Token for object with which binding is - * associated. */ - char *eventString; /* String describing event sequence that - * triggers binding. */ - TkBindEvalProc *eventProc; /* Procedure to invoke when binding - * triggers. Must not be NULL. */ - TkBindFreeProc *freeProc; /* Procedure to invoke when binding is - * freed. May be NULL for no procedure. */ - ClientData clientData; /* Arbitrary ClientData to pass to eventProc - * and freeProc. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr; - unsigned long eventMask; - - psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, - 1, 1, &eventMask); - if (psPtr == NULL) { - return 0; - } - if (psPtr->eventProc == NULL) { - int new; - Tcl_HashEntry *hPtr; - - /* - * This pattern sequence was just created. - * Link the pattern into the list associated with the object, so - * that if the object goes away, these bindings will all - * automatically be deleted. - */ - - hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object, - &new); - if (new) { - psPtr->nextObjPtr = NULL; - } else { - psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - } - Tcl_SetHashValue(hPtr, psPtr); - } else { - - /* - * Free existing callback. - */ - - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - } - - psPtr->eventProc = eventProc; - psPtr->freeProc = freeProc; - psPtr->clientData = clientData; - return eventMask; -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteBinding -- - * - * Remove an event binding from a binding table. - * - * Results: - * The result is a standard Tcl return value. If an error - * occurs then interp->result will contain an error message. - * - * Side effects: - * The binding given by object and eventString is removed - * from bindingTable. - * - *-------------------------------------------------------------- - */ - -int -Tk_DeleteBinding(interp, bindingTable, object, eventString) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_BindingTable bindingTable; /* Table in which to delete binding. */ - ClientData object; /* Token for object with which binding - * is associated. */ - char *eventString; /* String describing event sequence - * that triggers binding. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr, *prevPtr; - unsigned long eventMask; - Tcl_HashEntry *hPtr; - - psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, - 0, 1, &eventMask); - if (psPtr == NULL) { - Tcl_ResetResult(interp); - return TCL_OK; - } - - /* - * Unlink the binding from the list for its object, then from the - * list for its pattern. - */ - - hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); - if (hPtr == NULL) { - panic("Tk_DeleteBinding couldn't find object table entry"); - } - prevPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - if (prevPtr == psPtr) { - Tcl_SetHashValue(hPtr, psPtr->nextObjPtr); - } else { - for ( ; ; prevPtr = prevPtr->nextObjPtr) { - if (prevPtr == NULL) { - panic("Tk_DeleteBinding couldn't find on object list"); - } - if (prevPtr->nextObjPtr == psPtr) { - prevPtr->nextObjPtr = psPtr->nextObjPtr; - break; - } - } - } - prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); - if (prevPtr == psPtr) { - if (psPtr->nextSeqPtr == NULL) { - Tcl_DeleteHashEntry(psPtr->hPtr); - } else { - Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr); - } - } else { - for ( ; ; prevPtr = prevPtr->nextSeqPtr) { - if (prevPtr == NULL) { - panic("Tk_DeleteBinding couldn't find on hash chain"); - } - if (prevPtr->nextSeqPtr == psPtr) { - prevPtr->nextSeqPtr = psPtr->nextSeqPtr; - break; - } - } - } - - psPtr->flags |= MARKED_DELETED; - if (psPtr->refCount == 0) { - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - ckfree((char *) psPtr); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetBinding -- - * - * Return the command associated with a given event string. - * - * Results: - * The return value is a pointer to the command string - * associated with eventString for object in the domain - * given by bindingTable. If there is no binding for - * eventString, or if eventString is improperly formed, - * then NULL is returned and an error message is left in - * interp->result. The return value is semi-static: it - * will persist until the binding is changed or deleted. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_GetBinding(interp, bindingTable, object, eventString) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_BindingTable bindingTable; /* Table in which to look for - * binding. */ - ClientData object; /* Token for object with which binding - * is associated. */ - char *eventString; /* String describing event sequence - * that triggers binding. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr; - unsigned long eventMask; - - psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, - 0, 1, &eventMask); - if (psPtr == NULL) { - return NULL; - } - if (psPtr->eventProc == EvalTclBinding) { - return (char *) psPtr->clientData; - } - return ""; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetAllBindings -- - * - * Return a list of event strings for all the bindings - * associated with a given object. - * - * Results: - * There is no return value. Interp->result is modified to - * hold a Tcl list with one entry for each binding associated - * with object in bindingTable. Each entry in the list - * contains the event string associated with one binding. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -Tk_GetAllBindings(interp, bindingTable, object) - Tcl_Interp *interp; /* Interpreter returning result or - * error. */ - Tk_BindingTable bindingTable; /* Table in which to look for - * bindings. */ - ClientData object; /* Token for object. */ - -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr; - Tcl_HashEntry *hPtr; - Tcl_DString ds; - - hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); - if (hPtr == NULL) { - return; - } - Tcl_DStringInit(&ds); - for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; - psPtr = psPtr->nextObjPtr) { - /* - * For each binding, output information about each of the - * patterns in its sequence. - */ - - Tcl_DStringSetLength(&ds, 0); - GetPatternString(psPtr, &ds); - Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); - } - Tcl_DStringFree(&ds); -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteAllBindings -- - * - * Remove all bindings associated with a given object in a - * given binding table. - * - * Results: - * All bindings associated with object are removed from - * bindingTable. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -Tk_DeleteAllBindings(bindingTable, object) - Tk_BindingTable bindingTable; /* Table in which to delete - * bindings. */ - ClientData object; /* Token for object. */ -{ - BindingTable *bindPtr = (BindingTable *) bindingTable; - PatSeq *psPtr, *prevPtr; - PatSeq *nextPtr; - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); - if (hPtr == NULL) { - return; - } - for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; - psPtr = nextPtr) { - nextPtr = psPtr->nextObjPtr; - - /* - * Be sure to remove each binding from its hash chain in the - * pattern table. If this is the last pattern in the chain, - * then delete the hash entry too. - */ - - prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); - if (prevPtr == psPtr) { - if (psPtr->nextSeqPtr == NULL) { - Tcl_DeleteHashEntry(psPtr->hPtr); - } else { - Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr); - } - } else { - for ( ; ; prevPtr = prevPtr->nextSeqPtr) { - if (prevPtr == NULL) { - panic("Tk_DeleteAllBindings couldn't find on hash chain"); - } - if (prevPtr->nextSeqPtr == psPtr) { - prevPtr->nextSeqPtr = psPtr->nextSeqPtr; - break; - } - } - } - psPtr->flags |= MARKED_DELETED; - - if (psPtr->refCount == 0) { - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - ckfree((char *) psPtr); - } - } - Tcl_DeleteHashEntry(hPtr); -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_BindEvent -- - * - * This procedure is invoked to process an X event. The - * event is added to those recorded for the binding table. - * Then each of the objects at *objectPtr is checked in - * order to see if it has a binding that matches the recent - * events. If so, the most specific binding is invoked for - * each object. - * - * Results: - * None. - * - * Side effects: - * Depends on the command associated with the matching binding. - * - * All Tcl bindings scripts for each object are accumulated before - * the first binding is evaluated. If the action of a Tcl binding - * is to change or delete a binding, or delete the window associated - * with the binding, all the original Tcl binding scripts will still - * fire. Contrast this with C binding procedures. If a pending C - * binding (one that hasn't fired yet, but is queued to be fired for - * this window) is deleted, it will not be called, and if it is - * changed, then the new binding procedure will be called. If the - * window itself is deleted, no further C binding procedures will be - * called for this window. When both Tcl binding scripts and C binding - * procedures are interleaved, the above rules still apply. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) - Tk_BindingTable bindingTable; /* Table in which to look for - * bindings. */ - XEvent *eventPtr; /* What actually happened. */ - Tk_Window tkwin; /* Window on display where event - * occurred (needed in order to - * locate display information). */ - int numObjects; /* Number of objects at *objectPtr. */ - ClientData *objectPtr; /* Array of one or more objects - * to check for a matching binding. */ -{ - BindingTable *bindPtr; - TkDisplay *dispPtr; - BindInfo *bindInfoPtr; - TkDisplay *oldDispPtr; - ScreenInfo *screenPtr; - XEvent *ringPtr; - PatSeq *vMatchDetailList, *vMatchNoDetailList; - int flags, oldScreen, i, deferModal; - unsigned int matchCount, matchSpace; - Tcl_Interp *interp; - Tcl_DString scripts, savedResult; - Detail detail; - char *p, *end; - PendingBinding *pendingPtr; - PendingBinding staticPending; - TkWindow *winPtr = (TkWindow *)tkwin; - PatternTableKey key; - - /* - * Ignore events on windows that don't have names: these are windows - * like wrapper windows that shouldn't be visible to the - * application. - */ - - if (winPtr->pathName == NULL) { - return; - } - - /* - * Ignore the event completely if it is an Enter, Leave, FocusIn, - * or FocusOut event with detail NotifyInferior. The reason for - * ignoring these events is that we don't want transitions between - * a window and its children to visible to bindings on the parent: - * this would cause problems for mega-widgets, since the internal - * structure of a mega-widget isn't supposed to be visible to - * people watching the parent. - */ - - if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { - if (eventPtr->xcrossing.detail == NotifyInferior) { - return; - } - } - if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { - if (eventPtr->xfocus.detail == NotifyInferior) { - return; - } - } - - bindPtr = (BindingTable *) bindingTable; - dispPtr = ((TkWindow *) tkwin)->dispPtr; - bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo; - - /* - * Add the new event to the ring of saved events for the - * binding table. Two tricky points: - * - * 1. Combine consecutive MotionNotify events. Do this by putting - * the new event *on top* of the previous event. - * 2. If a modifier key is held down, it auto-repeats to generate - * continuous KeyPress and KeyRelease events. These can flush - * the event ring so that valuable information is lost (such - * as repeated button clicks). To handle this, check for the - * special case of a modifier KeyPress arriving when the previous - * two events are a KeyRelease and KeyPress of the same key. - * If this happens, mark the most recent event (the KeyRelease) - * invalid and put the new event on top of the event before that - * (the KeyPress). - */ - - if ((eventPtr->type == MotionNotify) - && (bindPtr->eventRing[bindPtr->curEvent].type == MotionNotify)) { - /* - * Don't advance the ring pointer. - */ - } else if (eventPtr->type == KeyPress) { - int i; - for (i = 0; ; i++) { - if (i >= dispPtr->numModKeyCodes) { - goto advanceRingPointer; - } - if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { - break; - } - } - ringPtr = &bindPtr->eventRing[bindPtr->curEvent]; - if ((ringPtr->type != KeyRelease) - || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) { - goto advanceRingPointer; - } - if (bindPtr->curEvent <= 0) { - i = EVENT_BUFFER_SIZE - 1; - } else { - i = bindPtr->curEvent - 1; - } - ringPtr = &bindPtr->eventRing[i]; - if ((ringPtr->type != KeyPress) - || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) { - goto advanceRingPointer; - } - bindPtr->eventRing[bindPtr->curEvent].type = -1; - bindPtr->curEvent = i; - } else { - advanceRingPointer: - bindPtr->curEvent++; - if (bindPtr->curEvent >= EVENT_BUFFER_SIZE) { - bindPtr->curEvent = 0; - } - } - ringPtr = &bindPtr->eventRing[bindPtr->curEvent]; - memcpy((VOID *) ringPtr, (VOID *) eventPtr, sizeof(XEvent)); - detail.clientData = 0; - flags = flagArray[ringPtr->type]; - if (flags & KEY) { - detail.keySym = GetKeySym(dispPtr, ringPtr); - if (detail.keySym == NoSymbol) { - detail.keySym = 0; - } - } else if (flags & BUTTON) { - detail.button = ringPtr->xbutton.button; - } else if (flags & VIRTUAL) { - detail.name = ((XVirtualEvent *) ringPtr)->name; - } - bindPtr->detailRing[bindPtr->curEvent] = detail; - - /* - * Find out if there are any virtual events that correspond to this - * physical event (or sequence of physical events). - */ - - vMatchDetailList = NULL; - vMatchNoDetailList = NULL; - memset(&key, 0, sizeof(key)); - - if (ringPtr->type != VirtualEvent) { - Tcl_HashTable *veptPtr; - Tcl_HashEntry *hPtr; - - veptPtr = &bindInfoPtr->virtualEventTable.patternTable; - - key.object = NULL; - key.type = ringPtr->type; - key.detail = detail; - - hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key); - if (hPtr != NULL) { - vMatchDetailList = (PatSeq *) Tcl_GetHashValue(hPtr); - } - - if (key.detail.clientData != 0) { - key.detail.clientData = 0; - hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key); - if (hPtr != NULL) { - vMatchNoDetailList = (PatSeq *) Tcl_GetHashValue(hPtr); - } - } - } - - /* - * Loop over all the binding tags, finding the binding script or - * callback for each one. Append all of the binding scripts, with - * %-sequences expanded, to "scripts", with null characters separating - * the scripts for each object. Append all the callbacks to the array - * of pending callbacks. - */ - - pendingPtr = &staticPending; - matchCount = 0; - matchSpace = sizeof(staticPending.matchArray) / sizeof(PatSeq *); - Tcl_DStringInit(&scripts); - - for ( ; numObjects > 0; numObjects--, objectPtr++) { - PatSeq *matchPtr, *sourcePtr; - Tcl_HashEntry *hPtr; - - matchPtr = NULL; - sourcePtr = NULL; - - /* - * Match the new event against those recorded in the pattern table, - * saving the longest matching pattern. For events with details - * (button and key events), look for a binding for the specific - * key or button. First see if the event matches a physical event - * that the object is interested in, then look for a virtual event. - */ - - key.object = *objectPtr; - key.type = ringPtr->type; - key.detail = detail; - hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); - if (hPtr != NULL) { - matchPtr = MatchPatterns(dispPtr, bindPtr, - (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL, - &sourcePtr); - } - - if (vMatchDetailList != NULL) { - matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchDetailList, - matchPtr, objectPtr, &sourcePtr); - } - - /* - * If no match was found, look for a binding for all keys or buttons - * (detail of 0). Again, first match on a virtual event. - */ - - if ((detail.clientData != 0) && (matchPtr == NULL)) { - key.detail.clientData = 0; - hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); - if (hPtr != NULL) { - matchPtr = MatchPatterns(dispPtr, bindPtr, - (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL, - &sourcePtr); - } - - if (vMatchNoDetailList != NULL) { - matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchNoDetailList, - matchPtr, objectPtr, &sourcePtr); - } - - } - - if (matchPtr != NULL) { - if (sourcePtr->eventProc == NULL) { - panic("Tk_BindEvent: missing command"); - } - if (sourcePtr->eventProc == EvalTclBinding) { - ExpandPercents(winPtr, (char *) sourcePtr->clientData, - eventPtr, detail.keySym, &scripts); - } else { - if (matchCount >= matchSpace) { - PendingBinding *new; - unsigned int oldSize, newSize; - - oldSize = sizeof(staticPending) - - sizeof(staticPending.matchArray) - + matchSpace * sizeof(PatSeq*); - matchSpace *= 2; - newSize = sizeof(staticPending) - - sizeof(staticPending.matchArray) - + matchSpace * sizeof(PatSeq*); - new = (PendingBinding *) ckalloc(newSize); - memcpy((VOID *) new, (VOID *) pendingPtr, oldSize); - if (pendingPtr != &staticPending) { - ckfree((char *) pendingPtr); - } - pendingPtr = new; - } - sourcePtr->refCount++; - pendingPtr->matchArray[matchCount] = sourcePtr; - matchCount++; - } - /* - * A "" is added to the scripts string to separate the - * various scripts that should be invoked. - */ - - Tcl_DStringAppend(&scripts, "", 1); - } - } - if (Tcl_DStringLength(&scripts) == 0) { - return; - } - - /* - * Now go back through and evaluate the binding for each object, - * in order, dealing with "break" and "continue" exceptions - * appropriately. - * - * There are two tricks here: - * 1. Bindings can be invoked from in the middle of Tcl commands, - * where interp->result is significant (for example, a widget - * might be deleted because of an error in creating it, so the - * result contains an error message that is eventually going to - * be returned by the creating command). To preserve the result, - * we save it in a dynamic string. - * 2. The binding's action can potentially delete the binding, - * so bindPtr may not point to anything valid once the action - * completes. Thus we have to save bindPtr->interp in a - * local variable in order to restore the result. - */ - - interp = bindPtr->interp; - Tcl_DStringInit(&savedResult); - - /* - * Save information about the current screen, then invoke a script - * if the screen has changed. - */ - - Tcl_DStringGetResult(interp, &savedResult); - screenPtr = &bindInfoPtr->screenInfo; - oldDispPtr = screenPtr->curDispPtr; - oldScreen = screenPtr->curScreenIndex; - if ((dispPtr != screenPtr->curDispPtr) - || (Tk_ScreenNumber(tkwin) != screenPtr->curScreenIndex)) { - screenPtr->curDispPtr = dispPtr; - screenPtr->curScreenIndex = Tk_ScreenNumber(tkwin); - ChangeScreen(interp, dispPtr->name, screenPtr->curScreenIndex); - } - - if (matchCount > 0) { - pendingPtr->nextPtr = bindInfoPtr->pendingList; - pendingPtr->tkwin = tkwin; - pendingPtr->deleted = 0; - bindInfoPtr->pendingList = pendingPtr; - } - - /* - * Save the current value of the TK_DEFER_MODAL flag so we can - * restore it at the end of the loop. Clear the flag so we can - * detect any recursive requests for a modal loop. - */ - - flags = winPtr->flags; - winPtr->flags &= ~TK_DEFER_MODAL; - - p = Tcl_DStringValue(&scripts); - end = p + Tcl_DStringLength(&scripts); - i = 0; - - while (p < end) { - int code; - - screenPtr->bindingDepth++; - Tcl_AllowExceptions(interp); - - if (*p == '\0') { - PatSeq *psPtr; - - psPtr = pendingPtr->matchArray[i]; - i++; - code = TCL_OK; - if ((pendingPtr->deleted == 0) - && ((psPtr->flags & MARKED_DELETED) == 0)) { - code = (*psPtr->eventProc)(psPtr->clientData, interp, eventPtr, - tkwin, detail.keySym); - } - psPtr->refCount--; - if ((psPtr->refCount == 0) && (psPtr->flags & MARKED_DELETED)) { - if (psPtr->freeProc != NULL) { - (*psPtr->freeProc)(psPtr->clientData); - } - ckfree((char *) psPtr); - } - } else { - code = Tcl_GlobalEval(interp, p); - p += strlen(p); - } - p++; - screenPtr->bindingDepth--; - if (code != TCL_OK) { - if (code == TCL_CONTINUE) { - /* - * Do nothing: just go on to the next command. - */ - } else if (code == TCL_BREAK) { - break; - } else { - Tcl_AddErrorInfo(interp, "\n (command bound to event)"); - Tcl_BackgroundError(interp); - break; - } - } - } - - if (matchCount > 0 && !pendingPtr->deleted) { - /* - * Restore the original modal flag value and invoke the modal loop - * if needed. - */ - - deferModal = winPtr->flags & TK_DEFER_MODAL; - winPtr->flags = (winPtr->flags & (unsigned int) ~TK_DEFER_MODAL) - | (flags & TK_DEFER_MODAL); - if (deferModal) { - (*winPtr->classProcsPtr->modalProc)(tkwin, eventPtr); - } - } - - if ((screenPtr->bindingDepth != 0) && - ((oldDispPtr != screenPtr->curDispPtr) - || (oldScreen != screenPtr->curScreenIndex))) { - - /* - * Some other binding script is currently executing, but its - * screen is no longer current. Change the current display - * back again. - */ - - screenPtr->curDispPtr = oldDispPtr; - screenPtr->curScreenIndex = oldScreen; - ChangeScreen(interp, oldDispPtr->name, oldScreen); - } - Tcl_DStringResult(interp, &savedResult); - Tcl_DStringFree(&scripts); - - if (matchCount > 0) { - PendingBinding **curPtrPtr; - - for (curPtrPtr = &bindInfoPtr->pendingList; ; ) { - if (*curPtrPtr == pendingPtr) { - *curPtrPtr = pendingPtr->nextPtr; - break; - } - curPtrPtr = &(*curPtrPtr)->nextPtr; - } - if (pendingPtr != &staticPending) { - ckfree((char *) pendingPtr); - } - } -} - -/* - *--------------------------------------------------------------------------- - * - * TkBindDeadWindow -- - * - * This procedure is invoked when it is determined that a window is - * dead. It cleans up bind-related information about the window - * - * Results: - * None. - * - * Side effects: - * Any pending C bindings for this window are cancelled. - * - *--------------------------------------------------------------------------- - */ - -void -TkBindDeadWindow(winPtr) - TkWindow *winPtr; /* The window that is being deleted. */ -{ - BindInfo *bindInfoPtr; - PendingBinding *curPtr; - - bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo; - curPtr = bindInfoPtr->pendingList; - while (curPtr != NULL) { - if (curPtr->tkwin == (Tk_Window) winPtr) { - curPtr->deleted = 1; - } - curPtr = curPtr->nextPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * MatchPatterns -- - * - * Given a list of pattern sequences and a list of recent events, - * return the pattern sequence that best matches the event list, - * if there is one. - * - * This procedure is used in two different ways. In the simplest - * use, "object" is NULL and psPtr is a list of pattern sequences, - * each of which corresponds to a binding. In this case, the - * procedure finds the pattern sequences that match the event list - * and returns the most specific of those, if there is more than one. - * - * In the second case, psPtr is a list of pattern sequences, each - * of which corresponds to a definition for a virtual binding. - * In order for one of these sequences to "match", it must match - * the events (as above) but in addition there must be a binding - * for its associated virtual event on the current object. The - * "object" argument indicates which object the binding must be for. - * - * Results: - * The return value is NULL if bestPtr is NULL and no pattern matches - * the recent events from bindPtr. Otherwise the return value is - * the most specific pattern sequence among bestPtr and all those - * at psPtr that match the event list and object. If a pattern - * sequence other than bestPtr is returned, then *bestCommandPtr - * is filled in with a pointer to the command from the best sequence. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static PatSeq * -MatchPatterns(dispPtr, bindPtr, psPtr, bestPtr, objectPtr, sourcePtrPtr) - TkDisplay *dispPtr; /* Display from which the event came. */ - BindingTable *bindPtr; /* Information about binding table, such as - * ring of recent events. */ - PatSeq *psPtr; /* List of pattern sequences. */ - PatSeq *bestPtr; /* The best match seen so far, from a - * previous call to this procedure. NULL - * means no prior best match. */ - ClientData *objectPtr; /* If NULL, the sequences at psPtr - * correspond to "normal" bindings. If - * non-NULL, the sequences at psPtr correspond - * to virtual bindings; in order to match each - * sequence must correspond to a virtual - * binding for which a binding exists for - * object in bindPtr. */ - PatSeq **sourcePtrPtr; /* Filled with the pattern sequence that - * contains the eventProc and clientData - * associated with the best match. If this - * differs from the return value, it is the - * virtual event that most closely matched the - * return value (a physical event). Not - * modified unless a result other than bestPtr - * is returned. */ -{ - PatSeq *matchPtr, *bestSourcePtr, *sourcePtr; - - bestSourcePtr = *sourcePtrPtr; - - /* - * Iterate over all the pattern sequences. - */ - - for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) { - XEvent *eventPtr; - Pattern *patPtr; - Window window; - Detail *detailPtr; - int patCount, ringCount, flags, state; - int modMask; - - /* - * Iterate over all the patterns in a sequence to be - * sure that they all match. - */ - - eventPtr = &bindPtr->eventRing[bindPtr->curEvent]; - detailPtr = &bindPtr->detailRing[bindPtr->curEvent]; - window = eventPtr->xany.window; - patPtr = psPtr->pats; - patCount = psPtr->numPats; - ringCount = EVENT_BUFFER_SIZE; - while (patCount > 0) { - if (ringCount <= 0) { - goto nextSequence; - } - if (eventPtr->xany.type != patPtr->eventType) { - /* - * Most of the event types are considered superfluous - * in that they are ignored if they occur in the middle - * of a pattern sequence and have mismatching types. The - * only ones that cannot be ignored are ButtonPress and - * ButtonRelease events (if the next event in the pattern - * is a KeyPress or KeyRelease) and KeyPress and KeyRelease - * events (if the next pattern event is a ButtonPress or - * ButtonRelease). Here are some tricky cases to consider: - * 1. Double-Button or Double-Key events. - * 2. Double-ButtonRelease or Double-KeyRelease events. - * 3. The arrival of various events like Enter and Leave - * and FocusIn and GraphicsExpose between two button - * presses or key presses. - * 4. Modifier keys like Shift and Control shouldn't - * generate conflicts with button events. - */ - - if ((patPtr->eventType == KeyPress) - || (patPtr->eventType == KeyRelease)) { - if ((eventPtr->xany.type == ButtonPress) - || (eventPtr->xany.type == ButtonRelease)) { - goto nextSequence; - } - } else if ((patPtr->eventType == ButtonPress) - || (patPtr->eventType == ButtonRelease)) { - if ((eventPtr->xany.type == KeyPress) - || (eventPtr->xany.type == KeyRelease)) { - int i; - - /* - * Ignore key events if they are modifier keys. - */ - - for (i = 0; i < dispPtr->numModKeyCodes; i++) { - if (dispPtr->modKeyCodes[i] - == eventPtr->xkey.keycode) { - /* - * This key is a modifier key, so ignore it. - */ - goto nextEvent; - } - } - goto nextSequence; - } - } - goto nextEvent; - } - if (eventPtr->xany.window != window) { - goto nextSequence; - } - - /* - * Note: it's important for the keysym check to go before - * the modifier check, so we can ignore unwanted modifier - * keys before choking on the modifier check. - */ - - if ((patPtr->detail.clientData != 0) - && (patPtr->detail.clientData != detailPtr->clientData)) { - /* - * The detail appears not to match. However, if the event - * is a KeyPress for a modifier key then just ignore the - * event. Otherwise event sequences like "aD" never match - * because the shift key goes down between the "a" and the - * "D". - */ - - if (eventPtr->xany.type == KeyPress) { - int i; - - for (i = 0; i < dispPtr->numModKeyCodes; i++) { - if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { - goto nextEvent; - } - } - } - goto nextSequence; - } - flags = flagArray[eventPtr->type]; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - state = eventPtr->xkey.state; - } else if (flags & CROSSING) { - state = eventPtr->xcrossing.state; - } else { - state = 0; - } - if (patPtr->needMods != 0) { - modMask = patPtr->needMods; - if ((modMask & META_MASK) && (dispPtr->metaModMask != 0)) { - modMask = (modMask & ~META_MASK) | dispPtr->metaModMask; - } - if ((modMask & ALT_MASK) && (dispPtr->altModMask != 0)) { - modMask = (modMask & ~ALT_MASK) | dispPtr->altModMask; - } - if ((state & modMask) != modMask) { - goto nextSequence; - } - } - if (psPtr->flags & PAT_NEARBY) { - XEvent *firstPtr; - int timeDiff; - - firstPtr = &bindPtr->eventRing[bindPtr->curEvent]; - timeDiff = (Time) firstPtr->xkey.time - eventPtr->xkey.time; - if ((firstPtr->xkey.x_root - < (eventPtr->xkey.x_root - NEARBY_PIXELS)) - || (firstPtr->xkey.x_root - > (eventPtr->xkey.x_root + NEARBY_PIXELS)) - || (firstPtr->xkey.y_root - < (eventPtr->xkey.y_root - NEARBY_PIXELS)) - || (firstPtr->xkey.y_root - > (eventPtr->xkey.y_root + NEARBY_PIXELS)) - || (timeDiff > NEARBY_MS)) { - goto nextSequence; - } - } - patPtr++; - patCount--; - nextEvent: - if (eventPtr == bindPtr->eventRing) { - eventPtr = &bindPtr->eventRing[EVENT_BUFFER_SIZE-1]; - detailPtr = &bindPtr->detailRing[EVENT_BUFFER_SIZE-1]; - } else { - eventPtr--; - detailPtr--; - } - ringCount--; - } - - matchPtr = psPtr; - sourcePtr = psPtr; - - if (objectPtr != NULL) { - int iVirt; - VirtualOwners *voPtr; - PatternTableKey key; - - /* - * The sequence matches the physical constraints. - * Is this object interested in any of the virtual events - * that correspond to this sequence? - */ - - voPtr = psPtr->voPtr; - - memset(&key, 0, sizeof(key)); - key.object = *objectPtr; - key.type = VirtualEvent; - key.detail.clientData = 0; - - for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) { - Tcl_HashEntry *hPtr = voPtr->owners[iVirt]; - - key.detail.name = (Tk_Uid) Tcl_GetHashKey(hPtr->tablePtr, - hPtr); - hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, - (char *) &key); - if (hPtr != NULL) { - - /* - * This tag is interested in this virtual event and its - * corresponding physical event is a good match with the - * virtual event's definition. - */ - - PatSeq *virtMatchPtr; - - virtMatchPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - if ((virtMatchPtr->numPats != 1) - || (virtMatchPtr->nextSeqPtr != NULL)) { - panic("MatchPattern: badly constructed virtual event"); - } - sourcePtr = virtMatchPtr; - goto match; - } - } - - /* - * The physical event matches a virtual event's definition, but - * the tag isn't interested in it. - */ - goto nextSequence; - } - match: - - /* - * This sequence matches. If we've already got another match, - * pick whichever is most specific. Detail is most important, - * then needMods. - */ - - if (bestPtr != NULL) { - Pattern *patPtr2; - int i; - - if (matchPtr->numPats != bestPtr->numPats) { - if (bestPtr->numPats > matchPtr->numPats) { - goto nextSequence; - } else { - goto newBest; - } - } - for (i = 0, patPtr = matchPtr->pats, patPtr2 = bestPtr->pats; - i < matchPtr->numPats; i++, patPtr++, patPtr2++) { - if (patPtr->detail.clientData != patPtr2->detail.clientData) { - if (patPtr->detail.clientData == 0) { - goto nextSequence; - } else { - goto newBest; - } - } - if (patPtr->needMods != patPtr2->needMods) { - if ((patPtr->needMods & patPtr2->needMods) - == patPtr->needMods) { - goto nextSequence; - } else if ((patPtr->needMods & patPtr2->needMods) - == patPtr2->needMods) { - goto newBest; - } - } - } - /* - * Tie goes to current best pattern. - * - * (1) For virtual vs. virtual, the least recently defined - * virtual wins, because virtuals are examined in order of - * definition. This order is _not_ guaranteed in the - * documentation. - * - * (2) For virtual vs. physical, the physical wins because all - * the physicals are examined before the virtuals. This order - * is guaranteed in the documentation. - * - * (3) For physical vs. physical pattern, the most recently - * defined physical wins, because physicals are examined in - * reverse order of definition. This order is guaranteed in - * the documentation. - */ - - goto nextSequence; - } - newBest: - bestPtr = matchPtr; - bestSourcePtr = sourcePtr; - - nextSequence: continue; - } - - *sourcePtrPtr = bestSourcePtr; - return bestPtr; -} - -/* - *-------------------------------------------------------------- - * - * ExpandPercents -- - * - * Given a command and an event, produce a new command - * by replacing % constructs in the original command - * with information from the X event. - * - * Results: - * The new expanded command is appended to the dynamic string - * given by dsPtr. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr) - TkWindow *winPtr; /* Window where event occurred: needed to - * get input context. */ - char *before; /* Command containing percent expressions - * to be replaced. */ - XEvent *eventPtr; /* X event containing information to be - * used in % replacements. */ - KeySym keySym; /* KeySym: only relevant for KeyPress and - * KeyRelease events). */ - Tcl_DString *dsPtr; /* Dynamic string in which to append new - * command. */ -{ - int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl - * list element. */ - int number, flags, length; -#define NUM_SIZE 40 - char *string; - char numStorage[NUM_SIZE+1]; - - if (eventPtr->type < TK_LASTEVENT) { - flags = flagArray[eventPtr->type]; - } else { - flags = 0; - } - while (1) { - /* - * Find everything up to the next % character and append it - * to the result string. - */ - - for (string = before; (*string != 0) && (*string != '%'); string++) { - /* Empty loop body. */ - } - if (string != before) { - Tcl_DStringAppend(dsPtr, before, string-before); - before = string; - } - if (*before == 0) { - break; - } - - /* - * There's a percent sequence here. Process it. - */ - - number = 0; - string = "??"; - switch (before[1]) { - case '#': - number = eventPtr->xany.serial; - goto doNumber; - case 'a': - TkpPrintWindowId(numStorage, eventPtr->xconfigure.above); - string = numStorage; - goto doString; - case 'b': - number = eventPtr->xbutton.button; - goto doNumber; - case 'c': - if (flags & EXPOSE) { - number = eventPtr->xexpose.count; - } - goto doNumber; - case 'd': - if (flags & (CROSSING|FOCUS)) { - if (flags & FOCUS) { - number = eventPtr->xfocus.detail; - } else { - number = eventPtr->xcrossing.detail; - } - string = TkFindStateString(notifyDetail, number); - } - goto doString; - case 'f': - number = eventPtr->xcrossing.focus; - goto doNumber; - case 'h': - if (flags & EXPOSE) { - number = eventPtr->xexpose.height; - } else if (flags & (CONFIG)) { - number = eventPtr->xconfigure.height; - } - goto doNumber; - case 'k': - number = eventPtr->xkey.keycode; - goto doNumber; - case 'm': - if (flags & CROSSING) { - number = eventPtr->xcrossing.mode; - } else if (flags & FOCUS) { - number = eventPtr->xfocus.mode; - } - string = TkFindStateString(notifyMode, number); - goto doString; - case 'o': - if (flags & CREATE) { - number = eventPtr->xcreatewindow.override_redirect; - } else if (flags & MAP) { - number = eventPtr->xmap.override_redirect; - } else if (flags & REPARENT) { - number = eventPtr->xreparent.override_redirect; - } else if (flags & CONFIG) { - number = eventPtr->xconfigure.override_redirect; - } - goto doNumber; - case 'p': - string = TkFindStateString(circPlace, eventPtr->xcirculate.place); - goto doString; - case 's': - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - number = eventPtr->xkey.state; - } else if (flags & CROSSING) { - number = eventPtr->xcrossing.state; - } else if (flags & VISIBILITY) { - string = TkFindStateString(visNotify, - eventPtr->xvisibility.state); - goto doString; - } - goto doNumber; - case 't': - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - number = (int) eventPtr->xkey.time; - } else if (flags & CROSSING) { - number = (int) eventPtr->xcrossing.time; - } else if (flags & PROP) { - number = (int) eventPtr->xproperty.time; - } - goto doNumber; - case 'v': - number = eventPtr->xconfigurerequest.value_mask; - goto doNumber; - case 'w': - if (flags & EXPOSE) { - number = eventPtr->xexpose.width; - } else if (flags & CONFIG) { - number = eventPtr->xconfigure.width; - } - goto doNumber; - case 'x': - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - number = eventPtr->xkey.x; - } else if (flags & CROSSING) { - number = eventPtr->xcrossing.x; - } else if (flags & EXPOSE) { - number = eventPtr->xexpose.x; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - number = eventPtr->xcreatewindow.x; - } else if (flags & REPARENT) { - number = eventPtr->xreparent.x; - } - goto doNumber; - case 'y': - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - number = eventPtr->xkey.y; - } else if (flags & EXPOSE) { - number = eventPtr->xexpose.y; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - number = eventPtr->xcreatewindow.y; - } else if (flags & REPARENT) { - number = eventPtr->xreparent.y; - } else if (flags & CROSSING) { - number = eventPtr->xcrossing.y; - - } - goto doNumber; - case 'A': - if (flags & KEY) { - int numChars; - - /* - * If we're using input methods and this is a keypress - * event, invoke XmbTkFindStateString. Otherwise just use - * the older XTkFindStateString. - */ - -#ifdef TK_USE_INPUT_METHODS - Status status; - if ((winPtr->inputContext != NULL) - && (eventPtr->type == KeyPress)) { - numChars = XmbLookupString(winPtr->inputContext, - &eventPtr->xkey, numStorage, NUM_SIZE, - (KeySym *) NULL, &status); - if ((status != XLookupChars) - && (status != XLookupBoth)) { - numChars = 0; - } - } else { - numChars = XLookupString(&eventPtr->xkey, numStorage, - NUM_SIZE, (KeySym *) NULL, - (XComposeStatus *) NULL); - } -#else /* TK_USE_INPUT_METHODS */ - numChars = XLookupString(&eventPtr->xkey, numStorage, - NUM_SIZE, (KeySym *) NULL, - (XComposeStatus *) NULL); -#endif /* TK_USE_INPUT_METHODS */ - numStorage[numChars] = '\0'; - string = numStorage; - } - goto doString; - case 'B': - number = eventPtr->xcreatewindow.border_width; - goto doNumber; - case 'E': - number = (int) eventPtr->xany.send_event; - goto doNumber; - case 'K': - if (flags & KEY) { - char *name; - - name = TkKeysymToString(keySym); - if (name != NULL) { - string = name; - } - } - goto doString; - case 'N': - number = (int) keySym; - goto doNumber; - case 'R': - TkpPrintWindowId(numStorage, eventPtr->xkey.root); - string = numStorage; - goto doString; - case 'S': - TkpPrintWindowId(numStorage, eventPtr->xkey.subwindow); - string = numStorage; - goto doString; - case 'T': - number = eventPtr->type; - goto doNumber; - case 'W': { - Tk_Window tkwin; - - tkwin = Tk_IdToWindow(eventPtr->xany.display, - eventPtr->xany.window); - if (tkwin != NULL) { - string = Tk_PathName(tkwin); - } else { - string = "??"; - } - goto doString; - } - case 'X': { - Tk_Window tkwin; - int x, y; - int width, height; - - number = eventPtr->xkey.x_root; - tkwin = Tk_IdToWindow(eventPtr->xany.display, - eventPtr->xany.window); - if (tkwin != NULL) { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - number -= x; - } - goto doNumber; - } - case 'Y': { - Tk_Window tkwin; - int x, y; - int width, height; - - number = eventPtr->xkey.y_root; - tkwin = Tk_IdToWindow(eventPtr->xany.display, - eventPtr->xany.window); - if (tkwin != NULL) { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - number -= y; - } - goto doNumber; - } - default: - numStorage[0] = before[1]; - numStorage[1] = '\0'; - string = numStorage; - goto doString; - } - - doNumber: - sprintf(numStorage, "%d", number); - string = numStorage; - - doString: - spaceNeeded = Tcl_ScanElement(string, &cvtFlags); - length = Tcl_DStringLength(dsPtr); - Tcl_DStringSetLength(dsPtr, length + spaceNeeded); - spaceNeeded = Tcl_ConvertElement(string, - Tcl_DStringValue(dsPtr) + length, - cvtFlags | TCL_DONT_USE_BRACES); - Tcl_DStringSetLength(dsPtr, length + spaceNeeded); - before += 2; - } -} - -/* - *---------------------------------------------------------------------- - * - * ChangeScreen -- - * - * This procedure is invoked whenever the current screen changes - * in an application. It invokes a Tcl procedure named - * "tkScreenChanged", passing it the screen name as argument. - * tkScreenChanged does things like making the tkPriv variable - * point to an array for the current display. - * - * Results: - * None. - * - * Side effects: - * Depends on what tkScreenChanged does. If an error occurs - * them tkError will be invoked. - * - *---------------------------------------------------------------------- - */ - -static void -ChangeScreen(interp, dispName, screenIndex) - Tcl_Interp *interp; /* Interpreter in which to invoke - * command. */ - char *dispName; /* Name of new display. */ - int screenIndex; /* Index of new screen. */ -{ - Tcl_DString cmd; - int code; - char screen[30]; - - Tcl_DStringInit(&cmd); - Tcl_DStringAppend(&cmd, "tkScreenChanged ", 16); - Tcl_DStringAppend(&cmd, dispName, -1); - sprintf(screen, ".%d", screenIndex); - Tcl_DStringAppend(&cmd, screen, -1); - code = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmd)); - if (code != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (changing screen in event binding)"); - Tcl_BackgroundError(interp); - } -} - - -/* - *---------------------------------------------------------------------- - * - * Tk_EventCmd -- - * - * This procedure is invoked to process the "event" Tcl command. - * It is used to define and generate events. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_EventCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - int i; - size_t length; - char *option; - Tk_Window tkwin; - VirtualEventTable *vetPtr; - TkBindInfo bindInfo; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg1?\"", (char *) NULL); - return TCL_ERROR; - } - - option = argv[1]; - length = strlen(option); - if (length == 0) { - goto badopt; - } - - tkwin = (Tk_Window) clientData; - bindInfo = ((TkWindow *) tkwin)->mainPtr->bindInfo; - vetPtr = &((BindInfo *) bindInfo)->virtualEventTable; - - if (strncmp(option, "add", length) == 0) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " add virtual sequence ?sequence ...?\"", (char *) NULL); - return TCL_ERROR; - } - for (i = 3; i < argc; i++) { - if (CreateVirtualEvent(interp, vetPtr, argv[2], argv[i]) - != TCL_OK) { - return TCL_ERROR; - } - } - } else if (strncmp(option, "delete", length) == 0) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " delete virtual ?sequence sequence ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (argc == 3) { - return DeleteVirtualEvent(interp, vetPtr, argv[2], NULL); - } - for (i = 3; i < argc; i++) { - if (DeleteVirtualEvent(interp, vetPtr, argv[2], argv[i]) - != TCL_OK) { - return TCL_ERROR; - } - } - } else if (strncmp(option, "generate", length) == 0) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " generate window event ?options?\"", (char *) NULL); - return TCL_ERROR; - } - return HandleEventGenerate(interp, tkwin, argc - 2, argv + 2); - } else if (strncmp(option, "info", length) == 0) { - if (argc == 2) { - GetAllVirtualEvents(interp, vetPtr); - return TCL_OK; - } else if (argc == 3) { - return GetVirtualEvent(interp, vetPtr, argv[2]); - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " info ?virtual?\"", (char *) NULL); - return TCL_ERROR; - } - } else { - badopt: - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be add, delete, generate, info", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * InitVirtualEventTable -- - * - * Given storage for a virtual event table, set up the fields to - * prepare a new domain in which virtual events may be defined. - * - * Results: - * None. - * - * Side effects: - * *vetPtr is now initialized. - * - *--------------------------------------------------------------------------- - */ - -static void -InitVirtualEventTable(vetPtr) - VirtualEventTable *vetPtr; /* Pointer to virtual event table. Memory - * is supplied by the caller. */ -{ - Tcl_InitHashTable(&vetPtr->patternTable, - sizeof(PatternTableKey) / sizeof(int)); - Tcl_InitHashTable(&vetPtr->nameTable, TCL_ONE_WORD_KEYS); -} - -/* - *--------------------------------------------------------------------------- - * - * DeleteVirtualEventTable -- - * - * Delete the contents of a virtual event table. The caller is - * responsible for freeing any memory used by the table itself. - * - * Results: - * None. - * - * Side effects: - * Memory is freed. - * - *--------------------------------------------------------------------------- - */ - -static void -DeleteVirtualEventTable(vetPtr) - VirtualEventTable *vetPtr; /* The virtual event table to delete. */ -{ - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - PatSeq *psPtr, *nextPtr; - - hPtr = Tcl_FirstHashEntry(&vetPtr->patternTable, &search); - for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - for ( ; psPtr != NULL; psPtr = nextPtr) { - nextPtr = psPtr->nextSeqPtr; - ckfree((char *) psPtr->voPtr); - ckfree((char *) psPtr); - } - } - Tcl_DeleteHashTable(&vetPtr->patternTable); - - hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search); - for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - ckfree((char *) Tcl_GetHashValue(hPtr)); - } - Tcl_DeleteHashTable(&vetPtr->nameTable); -} - -/* - *---------------------------------------------------------------------- - * - * CreateVirtualEvent -- - * - * Add a new definition for a virtual event. If the virtual event - * is already defined, the new definition augments those that - * already exist. - * - * Results: - * The return value is TCL_ERROR if an error occured while - * creating the virtual binding. In this case, an error message - * will be left in interp->result. If all went well then the return - * value is TCL_OK. - * - * Side effects: - * The virtual event may cause future calls to Tk_BindEvent to - * behave differently than they did previously. - * - *---------------------------------------------------------------------- - */ - -static int -CreateVirtualEvent(interp, vetPtr, virtString, eventString) - Tcl_Interp *interp; /* Used for error reporting. */ - VirtualEventTable *vetPtr;/* Table in which to augment virtual event. */ - char *virtString; /* Name of new virtual event. */ - char *eventString; /* String describing physical event that - * triggers virtual event. */ -{ - PatSeq *psPtr; - int dummy; - Tcl_HashEntry *vhPtr; - unsigned long eventMask; - PhysicalsOwned *poPtr; - VirtualOwners *voPtr; - Tk_Uid virtUid; - - virtUid = GetVirtualEventUid(interp, virtString); - if (virtUid == NULL) { - return TCL_ERROR; - } - - /* - * Find/create physical event - */ - - psPtr = FindSequence(interp, &vetPtr->patternTable, NULL, eventString, - 1, 0, &eventMask); - if (psPtr == NULL) { - return TCL_ERROR; - } - - /* - * Find/create virtual event. - */ - - vhPtr = Tcl_CreateHashEntry(&vetPtr->nameTable, virtUid, &dummy); - - /* - * Make virtual event own the physical event. - */ - - poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); - if (poPtr == NULL) { - poPtr = (PhysicalsOwned *) ckalloc(sizeof(PhysicalsOwned)); - poPtr->numOwned = 0; - } else { - /* - * See if this virtual event is already defined for this physical - * event and just return if it is. - */ - - int i; - for (i = 0; i < poPtr->numOwned; i++) { - if (poPtr->patSeqs[i] == psPtr) { - return TCL_OK; - } - } - poPtr = (PhysicalsOwned *) ckrealloc((char *) poPtr, - sizeof(PhysicalsOwned) + poPtr->numOwned * sizeof(PatSeq *)); - } - Tcl_SetHashValue(vhPtr, (ClientData) poPtr); - poPtr->patSeqs[poPtr->numOwned] = psPtr; - poPtr->numOwned++; - - /* - * Make physical event so it can trigger the virtual event. - */ - - voPtr = psPtr->voPtr; - if (voPtr == NULL) { - voPtr = (VirtualOwners *) ckalloc(sizeof(VirtualOwners)); - voPtr->numOwners = 0; - } else { - voPtr = (VirtualOwners *) ckrealloc((char *) voPtr, - sizeof(VirtualOwners) - + voPtr->numOwners * sizeof(Tcl_HashEntry *)); - } - psPtr->voPtr = voPtr; - voPtr->owners[voPtr->numOwners] = vhPtr; - voPtr->numOwners++; - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteVirtualEvent -- - * - * Remove the definition of a given virtual event. If the - * event string is NULL, all definitions of the virtual event - * will be removed. Otherwise, just the specified definition - * of the virtual event will be removed. - * - * Results: - * The result is a standard Tcl return value. If an error - * occurs then interp->result will contain an error message. - * It is not an error to attempt to delete a virtual event that - * does not exist or a definition that does not exist. - * - * Side effects: - * The virtual event given by virtString may be removed from the - * virtual event table. - * - *-------------------------------------------------------------- - */ - -static int -DeleteVirtualEvent(interp, vetPtr, virtString, eventString) - Tcl_Interp *interp; /* Used for error reporting. */ - VirtualEventTable *vetPtr;/* Table in which to delete event. */ - char *virtString; /* String describing event sequence that - * triggers binding. */ - char *eventString; /* The event sequence that should be deleted, - * or NULL to delete all event sequences for - * the entire virtual event. */ -{ - int iPhys; - Tk_Uid virtUid; - Tcl_HashEntry *vhPtr; - PhysicalsOwned *poPtr; - PatSeq *eventPSPtr; - - virtUid = GetVirtualEventUid(interp, virtString); - if (virtUid == NULL) { - return TCL_ERROR; - } - - vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid); - if (vhPtr == NULL) { - return TCL_OK; - } - poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); - - eventPSPtr = NULL; - if (eventString != NULL) { - unsigned long eventMask; - - /* - * Delete only the specific physical event associated with the - * virtual event. If the physical event doesn't already exist, or - * the virtual event doesn't own that physical event, return w/o - * doing anything. - */ - - eventPSPtr = FindSequence(interp, &vetPtr->patternTable, NULL, - eventString, 0, 0, &eventMask); - if (eventPSPtr == NULL) { - return (interp->result[0] != '\0') ? TCL_ERROR : TCL_OK; - } - } - - for (iPhys = poPtr->numOwned; --iPhys >= 0; ) { - PatSeq *psPtr = poPtr->patSeqs[iPhys]; - if ((eventPSPtr == NULL) || (psPtr == eventPSPtr)) { - int iVirt; - VirtualOwners *voPtr; - - /* - * Remove association between this physical event and the given - * virtual event that it triggers. - */ - - voPtr = psPtr->voPtr; - for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) { - if (voPtr->owners[iVirt] == vhPtr) { - break; - } - } - if (iVirt == voPtr->numOwners) { - panic("DeleteVirtualEvent: couldn't find owner"); - } - voPtr->numOwners--; - if (voPtr->numOwners == 0) { - /* - * Removed last reference to this physical event, so - * remove it from physical->virtual map. - */ - PatSeq *prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); - if (prevPtr == psPtr) { - if (psPtr->nextSeqPtr == NULL) { - Tcl_DeleteHashEntry(psPtr->hPtr); - } else { - Tcl_SetHashValue(psPtr->hPtr, - psPtr->nextSeqPtr); - } - } else { - for ( ; ; prevPtr = prevPtr->nextSeqPtr) { - if (prevPtr == NULL) { - panic("Tk_DeleteVirtualEvent couldn't find on hash chain"); - } - if (prevPtr->nextSeqPtr == psPtr) { - prevPtr->nextSeqPtr = psPtr->nextSeqPtr; - break; - } - } - } - ckfree((char *) psPtr->voPtr); - ckfree((char *) psPtr); - } else { - /* - * This physical event still triggers some other virtual - * event(s). Consolidate the list of virtual owners for - * this physical event so it no longer triggers the - * given virtual event. - */ - voPtr->owners[iVirt] = voPtr->owners[voPtr->numOwners]; - } - - /* - * Now delete the virtual event's reference to the physical - * event. - */ - - poPtr->numOwned--; - if (eventPSPtr != NULL && poPtr->numOwned != 0) { - /* - * Just deleting this one physical event. Consolidate list - * of owned physical events and return. - */ - - poPtr->patSeqs[iPhys] = poPtr->patSeqs[poPtr->numOwned]; - return TCL_OK; - } - } - } - - if (poPtr->numOwned == 0) { - /* - * All the physical events for this virtual event were deleted, - * either because there was only one associated physical event or - * because the caller was deleting the entire virtual event. Now - * the virtual event itself should be deleted. - */ - - ckfree((char *) poPtr); - Tcl_DeleteHashEntry(vhPtr); - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * GetVirtualEvent -- - * - * Return the list of physical events that can invoke the - * given virtual event. - * - * Results: - * The return value is TCL_OK and interp->result is filled with the - * string representation of the physical events associated with the - * virtual event; if there are no physical events for the given virtual - * event, interp->result is filled with and empty string. If the - * virtual event string is improperly formed, then TCL_ERROR is - * returned and an error message is left in interp->result. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -GetVirtualEvent(interp, vetPtr, virtString) - Tcl_Interp *interp; /* Interpreter for reporting. */ - VirtualEventTable *vetPtr;/* Table in which to look for event. */ - char *virtString; /* String describing virtual event. */ -{ - Tcl_HashEntry *vhPtr; - Tcl_DString ds; - int iPhys; - PhysicalsOwned *poPtr; - Tk_Uid virtUid; - - virtUid = GetVirtualEventUid(interp, virtString); - if (virtUid == NULL) { - return TCL_ERROR; - } - - vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid); - if (vhPtr == NULL) { - return TCL_OK; - } - - Tcl_DStringInit(&ds); - - poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); - for (iPhys = 0; iPhys < poPtr->numOwned; iPhys++) { - Tcl_DStringSetLength(&ds, 0); - GetPatternString(poPtr->patSeqs[iPhys], &ds); - Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); - } - Tcl_DStringFree(&ds); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * GetAllVirtualEvents -- - * - * Return a list that contains the names of all the virtual - * event defined. - * - * Results: - * There is no return value. Interp->result is modified to - * hold a Tcl list with one entry for each virtual event in - * nameTable. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -GetAllVirtualEvents(interp, vetPtr) - Tcl_Interp *interp; /* Interpreter returning result. */ - VirtualEventTable *vetPtr;/* Table containing events. */ -{ - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - Tcl_DString ds; - - Tcl_DStringInit(&ds); - - hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search); - for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_DStringSetLength(&ds, 0); - Tcl_DStringAppend(&ds, "<<", 2); - Tcl_DStringAppend(&ds, Tcl_GetHashKey(hPtr->tablePtr, hPtr), -1); - Tcl_DStringAppend(&ds, ">>", 2); - Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); - } - - Tcl_DStringFree(&ds); -} - -/* - *--------------------------------------------------------------------------- - * - * HandleEventGenerate -- - * - * Helper function for the "event generate" command. Generate and - * process an XEvent, constructed from information parsed from the - * event description string and its optional arguments. - * - * argv[0] contains name of the target window. - * argv[1] contains pattern string for one event (e.g, <Control-v>). - * argv[2..argc-1] contains -field/option pairs for specifying - * additional detail in the generated event. - * - * Either virtual or physical events can be generated this way. - * The event description string must contain the specification - * for only one event. - * - * Results: - * None. - * - * Side effects: - * When constructing the event, - * event.xany.serial is filled with the current X serial number. - * event.xany.window is filled with the target window. - * event.xany.display is filled with the target window's display. - * Any other fields in eventPtr which are not specified by the pattern - * string or the optional arguments, are set to 0. - * - * The event may be handled sychronously or asynchronously, depending - * on the value specified by the optional "-when" option. The - * default setting is synchronous. - * - *--------------------------------------------------------------------------- - */ -static int -HandleEventGenerate(interp, mainwin, argc, argv) - Tcl_Interp *interp; /* Interp for error messages and name lookup. */ - Tk_Window mainwin; /* Main window associated with interp. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Pattern pat; - Tk_Window tkwin; - char *p; - unsigned long eventMask; - int count, i, state, flags, synch; - Tcl_QueuePosition pos; - XEvent event; - - if (argv[0][0] == '.') { - tkwin = Tk_NameToWindow(interp, argv[0], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - } else { - if (TkpScanWindowId(NULL, argv[0], &i) != TCL_OK) { - Tcl_AppendResult(interp, "bad window name/identifier \"", - argv[0], "\"", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_IdToWindow(Tk_Display(mainwin), (Window) i); - if ((tkwin == NULL) || (((TkWindow *) mainwin)->mainPtr - != ((TkWindow *) tkwin)->mainPtr)) { - Tcl_AppendResult(interp, "window id \"", argv[0], - "\" doesn't exist in this application", (char *) NULL); - return TCL_ERROR; - } - } - - p = argv[1]; - count = ParseEventDescription(interp, &p, &pat, &eventMask); - if (count == 0) { - return TCL_ERROR; - } - if (count != 1) { - interp->result = "Double or Triple modifier not allowed"; - return TCL_ERROR; - } - if (*p != '\0') { - interp->result = "only one event specification allowed"; - return TCL_ERROR; - } - if (argc & 1) { - Tcl_AppendResult(interp, "value for \"", argv[argc - 1], - "\" missing", (char *) NULL); - return TCL_ERROR; - } - - memset((VOID *) &event, 0, sizeof(event)); - event.xany.type = pat.eventType; - event.xany.serial = NextRequest(Tk_Display(tkwin)); - event.xany.send_event = False; - event.xany.window = Tk_WindowId(tkwin); - event.xany.display = Tk_Display(tkwin); - - flags = flagArray[event.xany.type]; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - event.xkey.state = pat.needMods; - if (flags & KEY) { - /* - * When mapping from a keysym to a keycode, need information about - * the modifier state that should be used so that when they call - * XKeycodeToKeysym taking into account the xkey.state, they will - * get back the original keysym. - */ - - if (pat.detail.keySym == NoSymbol) { - event.xkey.keycode = 0; - } else { - event.xkey.keycode = XKeysymToKeycode(event.xany.display, - pat.detail.keySym); - } - if (event.xkey.keycode != 0) { - for (state = 0; state < 4; state++) { - if (XKeycodeToKeysym(event.xany.display, - event.xkey.keycode, state) == pat.detail.keySym) { - if (state & 1) { - event.xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - event.xkey.state |= dispPtr->modeModMask; - } - break; - } - } - } - } else if (flags & BUTTON) { - event.xbutton.button = pat.detail.button; - } else if (flags & VIRTUAL) { - ((XVirtualEvent *) &event)->name = pat.detail.name; - } - } - if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) { - event.xcreatewindow.window = event.xany.window; - } - - /* - * Process the remaining arguments to fill in additional fields - * of the event. - */ - - synch = 1; - pos = TCL_QUEUE_TAIL; - for (i = 2; i < argc; i += 2) { - char *field, *value; - Tk_Window tkwin2; - int number; - KeySym keysym; - - field = argv[i]; - value = argv[i+1]; - - if (strcmp(field, "-when") == 0) { - if (strcmp(value, "now") == 0) { - synch = 1; - } else if (strcmp(value, "head") == 0) { - pos = TCL_QUEUE_HEAD; - synch = 0; - } else if (strcmp(value, "mark") == 0) { - pos = TCL_QUEUE_MARK; - synch = 0; - } else if (strcmp(value, "tail") == 0) { - pos = TCL_QUEUE_TAIL; - synch = 0; - } else { - Tcl_AppendResult(interp, "bad position \"", value, - "\": should be now, head, mark, tail", (char *) NULL); - return TCL_ERROR; - } - } else if (strcmp(field, "-above") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; - } - if (flags & CONFIG) { - event.xconfigure.above = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-borderwidth") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (CREATE|CONFIG)) { - event.xcreatewindow.border_width = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-button") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & BUTTON) { - event.xbutton.button = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-count") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & EXPOSE) { - event.xexpose.count = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-detail") == 0) { - number = TkFindStateNum(interp, field, notifyDetail, value); - if (number < 0) { - return TCL_ERROR; - } - if (flags & FOCUS) { - event.xfocus.detail = number; - } else if (flags & CROSSING) { - event.xcrossing.detail = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-focus") == 0) { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & CROSSING) { - event.xcrossing.focus = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-height") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & EXPOSE) { - event.xexpose.height = number; - } else if (flags & CONFIG) { - event.xconfigure.height = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-keycode") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & KEY) { - event.xkey.keycode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-keysym") == 0) { - keysym = TkStringToKeysym(value); - if (keysym == NoSymbol) { - Tcl_AppendResult(interp, "unknown keysym \"", value, - "\"", (char *) NULL); - return TCL_ERROR; - } - /* - * When mapping from a keysym to a keycode, need information about - * the modifier state that should be used so that when they call - * XKeycodeToKeysym taking into account the xkey.state, they will - * get back the original keysym. - */ - - number = XKeysymToKeycode(event.xany.display, keysym); - if (number == 0) { - Tcl_AppendResult(interp, "no keycode for keysym \"", value, - "\"", (char *) NULL); - return TCL_ERROR; - } - for (state = 0; state < 4; state++) { - if (XKeycodeToKeysym(event.xany.display, (unsigned) number, - state) == keysym) { - if (state & 1) { - event.xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - event.xkey.state |= dispPtr->modeModMask; - } - break; - } - } - if (flags & KEY) { - event.xkey.keycode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-mode") == 0) { - number = TkFindStateNum(interp, field, notifyMode, value); - if (number < 0) { - return TCL_ERROR; - } - if (flags & CROSSING) { - event.xcrossing.mode = number; - } else if (flags & FOCUS) { - event.xfocus.mode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-override") == 0) { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & CREATE) { - event.xcreatewindow.override_redirect = number; - } else if (flags & MAP) { - event.xmap.override_redirect = number; - } else if (flags & REPARENT) { - event.xreparent.override_redirect = number; - } else if (flags & CONFIG) { - event.xconfigure.override_redirect = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-place") == 0) { - number = TkFindStateNum(interp, field, circPlace, value); - if (number < 0) { - return TCL_ERROR; - } - if (flags & CIRC) { - event.xcirculate.place = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-root") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.root = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-rootx") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.x_root = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-rooty") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.y_root = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-sendevent") == 0) { - if (isdigit(UCHAR(value[0]))) { - /* - * Allow arbitrary integer values for the field; they - * are needed by a few of the tests in the Tk test suite. - */ - - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - } else { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - } - event.xany.send_event = number; - } else if (strcmp(field, "-serial") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - event.xany.serial = number; - } else if (strcmp(field, "-state") == 0) { - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - event.xkey.state = number; - } else { - event.xcrossing.state = number; - } - } else if (flags & VISIBILITY) { - number = TkFindStateNum(interp, field, visNotify, value); - if (number < 0) { - return TCL_ERROR; - } - event.xvisibility.state = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-subwindow") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.subwindow = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-time") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.time = (Time) number; - } else if (flags & PROP) { - event.xproperty.time = (Time) number; - } else { - goto badopt; - } - } else if (strcmp(field, "-width") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & EXPOSE) { - event.xexpose.width = number; - } else if (flags & (CREATE|CONFIG)) { - event.xcreatewindow.width = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-window") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; - } - if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG - |GRAVITY|CIRC)) { - event.xcreatewindow.window = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-x") == 0) { - int rootX, rootY; - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - Tk_GetRootCoords(tkwin, &rootX, &rootY); - rootX += number; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.x = number; - event.xkey.x_root = rootX; - } else if (flags & EXPOSE) { - event.xexpose.x = number; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - event.xcreatewindow.x = number; - } else if (flags & REPARENT) { - event.xreparent.x = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-y") == 0) { - int rootX, rootY; - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - Tk_GetRootCoords(tkwin, &rootX, &rootY); - rootY += number; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.y = number; - event.xkey.y_root = rootY; - } else if (flags & EXPOSE) { - event.xexpose.y = number; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - event.xcreatewindow.y = number; - } else if (flags & REPARENT) { - event.xreparent.y = number; - } else { - goto badopt; - } - } else { - badopt: - Tcl_AppendResult(interp, "bad option to ", argv[1], - " event: \"", field, "\"", (char *) NULL); - return TCL_ERROR; - } - } - - if (synch != 0) { - Tk_HandleEvent(&event); - } else { - Tk_QueueWindowEvent(&event, pos); - } - Tcl_ResetResult(interp); - return TCL_OK; -} - -/* - *------------------------------------------------------------------------- - * - * GetVirtualEventUid -- - * - * Determine if the given string is in the proper format for a - * virtual event. - * - * Results: - * The return value is NULL if the virtual event string was - * not in the proper format. In this case, an error message - * will be left in interp->result. Otherwise the return - * value is a Tk_Uid that represents the virtual event. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ -static Tk_Uid -GetVirtualEventUid(interp, virtString) - Tcl_Interp *interp; - char *virtString; -{ - Tk_Uid uid; - int length; - - length = strlen(virtString); - - if (length < 5 || virtString[0] != '<' || virtString[1] != '<' || - virtString[length - 2] != '>' || virtString[length - 1] != '>') { - Tcl_AppendResult(interp, "virtual event \"", virtString, - "\" is badly formed", (char *) NULL); - return NULL; - } - virtString[length - 2] = '\0'; - uid = Tk_GetUid(virtString + 2); - virtString[length - 2] = '>'; - - return uid; -} - - -/* - *---------------------------------------------------------------------- - * - * FindSequence -- - * - * Find the entry in the pattern table that corresponds to a - * particular pattern string, and return a pointer to that - * entry. - * - * Results: - * The return value is normally a pointer to the PatSeq - * in patternTable that corresponds to eventString. If an error - * was found while parsing eventString, or if "create" is 0 and - * no pattern sequence previously existed, then NULL is returned - * and interp->result contains a message describing the problem. - * If no pattern sequence previously existed for eventString, then - * a new one is created with a NULL command field. In a successful - * return, *maskPtr is filled in with a mask of the event types - * on which the pattern sequence depends. - * - * Side effects: - * A new pattern sequence may be allocated. - * - *---------------------------------------------------------------------- - */ - -static PatSeq * -FindSequence(interp, patternTablePtr, object, eventString, create, - allowVirtual, maskPtr) - Tcl_Interp *interp; /* Interpreter to use for error - * reporting. */ - Tcl_HashTable *patternTablePtr; /* Table to use for lookup. */ - ClientData object; /* For binding table, token for object with - * which binding is associated. - * For virtual event table, NULL. */ - char *eventString; /* String description of pattern to - * match on. See user documentation - * for details. */ - int create; /* 0 means don't create the entry if - * it doesn't already exist. Non-zero - * means create. */ - int allowVirtual; /* 0 means that virtual events are not - * allowed in the sequence. Non-zero - * otherwise. */ - unsigned long *maskPtr; /* *maskPtr is filled in with the event - * types on which this pattern sequence - * depends. */ -{ - - Pattern pats[EVENT_BUFFER_SIZE]; - int numPats, virtualFound; - char *p; - Pattern *patPtr; - PatSeq *psPtr; - Tcl_HashEntry *hPtr; - int flags, count, new; - size_t sequenceSize; - unsigned long eventMask; - PatternTableKey key; - - /* - *------------------------------------------------------------- - * Step 1: parse the pattern string to produce an array - * of Patterns. The array is generated backwards, so - * that the lowest-indexed pattern corresponds to the last - * event that must occur. - *------------------------------------------------------------- - */ - - p = eventString; - flags = 0; - eventMask = 0; - virtualFound = 0; - - patPtr = &pats[EVENT_BUFFER_SIZE-1]; - for (numPats = 0; numPats < EVENT_BUFFER_SIZE; numPats++, patPtr--) { - while (isspace(UCHAR(*p))) { - p++; - } - if (*p == '\0') { - break; - } - - count = ParseEventDescription(interp, &p, patPtr, &eventMask); - if (count == 0) { - return NULL; - } - - if (eventMask & VirtualEventMask) { - if (allowVirtual == 0) { - interp->result = - "virtual event not allowed in definition of another virtual event"; - return NULL; - } - virtualFound = 1; - } - - /* - * Replicate events for DOUBLE and TRIPLE. - */ - - if ((count > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { - flags |= PAT_NEARBY; - patPtr[-1] = patPtr[0]; - patPtr--; - numPats++; - if ((count == 3) && (numPats < EVENT_BUFFER_SIZE-1)) { - patPtr[-1] = patPtr[0]; - patPtr--; - numPats++; - } - } - } - - /* - *------------------------------------------------------------- - * Step 2: find the sequence in the binding table if it exists, - * and add a new sequence to the table if it doesn't. - *------------------------------------------------------------- - */ - - if (numPats == 0) { - interp->result = "no events specified in binding"; - return NULL; - } - if ((numPats > 1) && (virtualFound != 0)) { - interp->result = "virtual events may not be composed"; - return NULL; - } - - patPtr = &pats[EVENT_BUFFER_SIZE-numPats]; - memset(&key, 0, sizeof(key)); - key.object = object; - key.type = patPtr->eventType; - key.detail = patPtr->detail; - hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &new); - sequenceSize = numPats*sizeof(Pattern); - if (!new) { - for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; - psPtr = psPtr->nextSeqPtr) { - if ((numPats == psPtr->numPats) - && ((flags & PAT_NEARBY) == (psPtr->flags & PAT_NEARBY)) - && (memcmp((char *) patPtr, (char *) psPtr->pats, - sequenceSize) == 0)) { - goto done; - } - } - } - if (!create) { - if (new) { - Tcl_DeleteHashEntry(hPtr); - } - return NULL; - } - psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq) - + (numPats-1)*sizeof(Pattern))); - psPtr->numPats = numPats; - psPtr->eventProc = NULL; - psPtr->freeProc = NULL; - psPtr->clientData = NULL; - psPtr->flags = flags; - psPtr->refCount = 0; - psPtr->nextSeqPtr = (PatSeq *) Tcl_GetHashValue(hPtr); - psPtr->hPtr = hPtr; - psPtr->voPtr = NULL; - psPtr->nextObjPtr = NULL; - Tcl_SetHashValue(hPtr, psPtr); - - memcpy((VOID *) psPtr->pats, (VOID *) patPtr, sequenceSize); - - done: - *maskPtr = eventMask; - return psPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * ParseEventDescription -- - * - * Fill Pattern buffer with information about event from - * event string. - * - * Results: - * Leaves error message in interp and returns 0 if there was an - * error due to a badly formed event string. Returns 1 if proper - * event was specified, 2 if Double modifier was used in event - * string, or 3 if Triple was used. - * - * Side effects: - * On exit, eventStringPtr points to rest of event string (after the - * closing '>', so that this procedure can be called repeatedly to - * parse all the events in the entire sequence. - * - *--------------------------------------------------------------------------- - */ - -static int -ParseEventDescription(interp, eventStringPtr, patPtr, - eventMaskPtr) - Tcl_Interp *interp; /* For error messages. */ - char **eventStringPtr; /* On input, holds a pointer to start of - * event string. On exit, gets pointer to - * rest of string after parsed event. */ - Pattern *patPtr; /* Filled with the pattern parsed from the - * event string. */ - unsigned long *eventMaskPtr;/* Filled with event mask of matched event. */ - -{ - char *p; - unsigned long eventMask; - int count, eventFlags; -#define FIELD_SIZE 48 - char field[FIELD_SIZE]; - Tcl_HashEntry *hPtr; - - p = *eventStringPtr; - - patPtr->eventType = -1; - patPtr->needMods = 0; - patPtr->detail.clientData = 0; - - eventMask = 0; - count = 1; - - /* - * Handle simple ASCII characters. - */ - - if (*p != '<') { - char string[2]; - - patPtr->eventType = KeyPress; - eventMask = KeyPressMask; - string[0] = *p; - string[1] = 0; - patPtr->detail.keySym = TkStringToKeysym(string); - if (patPtr->detail.keySym == NoSymbol) { - if (isprint(UCHAR(*p))) { - patPtr->detail.keySym = *p; - } else { - sprintf(interp->result, - "bad ASCII character 0x%x", (unsigned char) *p); - return 0; - } - } - p++; - goto end; - } - - /* - * A fancier event description. This can be either a virtual event - * or a physical event. - * - * A virtual event description consists of: - * - * 1. double open angle brackets. - * 2. virtual event name. - * 3. double close angle brackets. - * - * A physical event description consists of: - * - * 1. open angle bracket. - * 2. any number of modifiers, each followed by spaces - * or dashes. - * 3. an optional event name. - * 4. an option button or keysym name. Either this or - * item 3 *must* be present; if both are present - * then they are separated by spaces or dashes. - * 5. a close angle bracket. - */ - - p++; - if (*p == '<') { - /* - * This is a virtual event: soak up all the characters up to - * the next '>'. - */ - - char *field = p + 1; - p = strchr(field, '>'); - if (p == field) { - interp->result = "virtual event \"<<>>\" is badly formed"; - return 0; - } - if ((p == NULL) || (p[1] != '>')) { - interp->result = "missing \">\" in virtual binding"; - return 0; - } - *p = '\0'; - patPtr->eventType = VirtualEvent; - eventMask = VirtualEventMask; - patPtr->detail.name = Tk_GetUid(field); - *p = '>'; - - p += 2; - goto end; - } - - while (1) { - ModInfo *modPtr; - p = GetField(p, field, FIELD_SIZE); - if (*p == '>') { - /* - * This solves the problem of, e.g., <Control-M> being - * misinterpreted as Control + Meta + missing keysym - * instead of Control + KeyPress + M. - */ - break; - } - hPtr = Tcl_FindHashEntry(&modTable, field); - if (hPtr == NULL) { - break; - } - modPtr = (ModInfo *) Tcl_GetHashValue(hPtr); - patPtr->needMods |= modPtr->mask; - if (modPtr->flags & (DOUBLE|TRIPLE)) { - if (modPtr->flags & DOUBLE) { - count = 2; - } else { - count = 3; - } - } - while ((*p == '-') || isspace(UCHAR(*p))) { - p++; - } - } - - eventFlags = 0; - hPtr = Tcl_FindHashEntry(&eventTable, field); - if (hPtr != NULL) { - EventInfo *eiPtr; - eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); - - patPtr->eventType = eiPtr->type; - eventFlags = flagArray[eiPtr->type]; - eventMask = eiPtr->eventMask; - while ((*p == '-') || isspace(UCHAR(*p))) { - p++; - } - p = GetField(p, field, FIELD_SIZE); - } - if (*field != '\0') { - if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) { - if (eventFlags == 0) { - patPtr->eventType = ButtonPress; - eventMask = ButtonPressMask; - } else if (eventFlags & KEY) { - goto getKeysym; - } else if ((eventFlags & BUTTON) == 0) { - Tcl_AppendResult(interp, "specified button \"", field, - "\" for non-button event", (char *) NULL); - return 0; - } - patPtr->detail.button = (*field - '0'); - } else { - getKeysym: - patPtr->detail.keySym = TkStringToKeysym(field); - if (patPtr->detail.keySym == NoSymbol) { - Tcl_AppendResult(interp, "bad event type or keysym \"", - field, "\"", (char *) NULL); - return 0; - } - if (eventFlags == 0) { - patPtr->eventType = KeyPress; - eventMask = KeyPressMask; - } else if ((eventFlags & KEY) == 0) { - Tcl_AppendResult(interp, "specified keysym \"", field, - "\" for non-key event", (char *) NULL); - return 0; - } - } - } else if (eventFlags == 0) { - interp->result = "no event type or button # or keysym"; - return 0; - } - - while ((*p == '-') || isspace(UCHAR(*p))) { - p++; - } - if (*p != '>') { - while (*p != '\0') { - p++; - if (*p == '>') { - interp->result = "extra characters after detail in binding"; - return 0; - } - } - interp->result = "missing \">\" in binding"; - return 0; - } - p++; - -end: - *eventStringPtr = p; - *eventMaskPtr |= eventMask; - return count; -} - -/* - *---------------------------------------------------------------------- - * - * GetField -- - * - * Used to parse pattern descriptions. Copies up to - * size characters from p to copy, stopping at end of - * string, space, "-", ">", or whenever size is - * exceeded. - * - * Results: - * The return value is a pointer to the character just - * after the last one copied (usually "-" or space or - * ">", but could be anything if size was exceeded). - * Also places NULL-terminated string (up to size - * character, including NULL), at copy. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static char * -GetField(p, copy, size) - char *p; /* Pointer to part of pattern. */ - char *copy; /* Place to copy field. */ - int size; /* Maximum number of characters to - * copy. */ -{ - while ((*p != '\0') && !isspace(UCHAR(*p)) && (*p != '>') - && (*p != '-') && (size > 1)) { - *copy = *p; - p++; - copy++; - size--; - } - *copy = '\0'; - return p; -} - -/* - *--------------------------------------------------------------------------- - * - * GetPatternString -- - * - * Produce a string version of the given event, for displaying to - * the user. - * - * Results: - * The string is left in dsPtr. - * - * Side effects: - * It is the caller's responsibility to initialize the DString before - * and to free it after calling this procedure. - * - *--------------------------------------------------------------------------- - */ -static void -GetPatternString(psPtr, dsPtr) - PatSeq *psPtr; - Tcl_DString *dsPtr; -{ - Pattern *patPtr; - char c, buffer[10]; - int patsLeft, needMods; - ModInfo *modPtr; - EventInfo *eiPtr; - - /* - * The order of the patterns in the sequence is backwards from the order - * in which they must be output. - */ - - for (patsLeft = psPtr->numPats, patPtr = &psPtr->pats[psPtr->numPats - 1]; - patsLeft > 0; patsLeft--, patPtr--) { - - /* - * Check for simple case of an ASCII character. - */ - - if ((patPtr->eventType == KeyPress) - && ((psPtr->flags & PAT_NEARBY) == 0) - && (patPtr->needMods == 0) - && (patPtr->detail.keySym < 128) - && isprint(UCHAR(patPtr->detail.keySym)) - && (patPtr->detail.keySym != '<') - && (patPtr->detail.keySym != ' ')) { - - c = (char) patPtr->detail.keySym; - Tcl_DStringAppend(dsPtr, &c, 1); - continue; - } - - /* - * Check for virtual event. - */ - - if (patPtr->eventType == VirtualEvent) { - Tcl_DStringAppend(dsPtr, "<<", 2); - Tcl_DStringAppend(dsPtr, patPtr->detail.name, -1); - Tcl_DStringAppend(dsPtr, ">>", 2); - continue; - } - - /* - * It's a more general event specification. First check - * for "Double" or "Triple", then modifiers, then event type, - * then keysym or button detail. - */ - - Tcl_DStringAppend(dsPtr, "<", 1); - if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1) - && (memcmp((char *) patPtr, (char *) (patPtr-1), - sizeof(Pattern)) == 0)) { - patsLeft--; - patPtr--; - if ((patsLeft > 1) && (memcmp((char *) patPtr, - (char *) (patPtr-1), sizeof(Pattern)) == 0)) { - patsLeft--; - patPtr--; - Tcl_DStringAppend(dsPtr, "Triple-", 7); - } else { - Tcl_DStringAppend(dsPtr, "Double-", 7); - } - } - for (needMods = patPtr->needMods, modPtr = modArray; - needMods != 0; modPtr++) { - if (modPtr->mask & needMods) { - needMods &= ~modPtr->mask; - Tcl_DStringAppend(dsPtr, modPtr->name, -1); - Tcl_DStringAppend(dsPtr, "-", 1); - } - } - for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { - if (eiPtr->type == patPtr->eventType) { - Tcl_DStringAppend(dsPtr, eiPtr->name, -1); - if (patPtr->detail.clientData != 0) { - Tcl_DStringAppend(dsPtr, "-", 1); - } - break; - } - } - - if (patPtr->detail.clientData != 0) { - if ((patPtr->eventType == KeyPress) - || (patPtr->eventType == KeyRelease)) { - char *string; - - string = TkKeysymToString(patPtr->detail.keySym); - if (string != NULL) { - Tcl_DStringAppend(dsPtr, string, -1); - } - } else { - sprintf(buffer, "%d", patPtr->detail.button); - Tcl_DStringAppend(dsPtr, buffer, -1); - } - } - Tcl_DStringAppend(dsPtr, ">", 1); - } -} - -/* - *---------------------------------------------------------------------- - * - * GetKeySym -- - * - * Given an X KeyPress or KeyRelease event, map the - * keycode in the event into a KeySym. - * - * Results: - * The return value is the KeySym corresponding to - * eventPtr, or NoSymbol if no matching Keysym could be - * found. - * - * Side effects: - * In the first call for a given display, keycode-to- - * KeySym maps get loaded. - * - *---------------------------------------------------------------------- - */ - -static KeySym -GetKeySym(dispPtr, eventPtr) - TkDisplay *dispPtr; /* Display in which to - * map keycode. */ - XEvent *eventPtr; /* Description of X event. */ -{ - KeySym sym; - int index; - - /* - * Refresh the mapping information if it's stale - */ - - if (dispPtr->bindInfoStale) { - InitKeymapInfo(dispPtr); - } - - /* - * Figure out which of the four slots in the keymap vector to - * use for this key. Refer to Xlib documentation for more info - * on how this computation works. - */ - - index = 0; - if (eventPtr->xkey.state & dispPtr->modeModMask) { - index = 2; - } - if ((eventPtr->xkey.state & ShiftMask) - || ((dispPtr->lockUsage != LU_IGNORE) - && (eventPtr->xkey.state & LockMask))) { - index += 1; - } - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index); - - /* - * Special handling: if the key was shifted because of Lock, but - * lock is only caps lock, not shift lock, and the shifted keysym - * isn't upper-case alphabetic, then switch back to the unshifted - * keysym. - */ - - if ((index & 1) && !(eventPtr->xkey.state & ShiftMask) - && (dispPtr->lockUsage == LU_CAPS)) { - if (!(((sym >= XK_A) && (sym <= XK_Z)) - || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { - index &= ~1; - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, - index); - } - } - - /* - * Another bit of special handling: if this is a shifted key and there - * is no keysym defined, then use the keysym for the unshifted key. - */ - - if ((index & 1) && (sym == NoSymbol)) { - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, - index & ~1); - } - return sym; -} - -/* - *-------------------------------------------------------------- - * - * InitKeymapInfo -- - * - * This procedure is invoked to scan keymap information - * to recompute stuff that's important for binding, such - * as the modifier key (if any) that corresponds to "mode - * switch". - * - * Results: - * None. - * - * Side effects: - * Keymap-related information in dispPtr is updated. - * - *-------------------------------------------------------------- - */ - -static void -InitKeymapInfo(dispPtr) - TkDisplay *dispPtr; /* Display for which to recompute keymap - * information. */ -{ - XModifierKeymap *modMapPtr; - KeyCode *codePtr; - KeySym keysym; - int count, i, j, max, arraySize; -#define KEYCODE_ARRAY_SIZE 20 - - dispPtr->bindInfoStale = 0; - modMapPtr = XGetModifierMapping(dispPtr->display); - - /* - * Check the keycodes associated with the Lock modifier. If - * any of them is associated with the XK_Shift_Lock modifier, - * then Lock has to be interpreted as Shift Lock, not Caps Lock. - */ - - dispPtr->lockUsage = LU_IGNORE; - codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex; - for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) { - if (*codePtr == 0) { - continue; - } - keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - if (keysym == XK_Shift_Lock) { - dispPtr->lockUsage = LU_SHIFT; - break; - } - if (keysym == XK_Caps_Lock) { - dispPtr->lockUsage = LU_CAPS; - break; - } - } - - /* - * Look through the keycodes associated with modifiers to see if - * the the "mode switch", "meta", or "alt" keysyms are associated - * with any modifiers. If so, remember their modifier mask bits. - */ - - dispPtr->modeModMask = 0; - dispPtr->metaModMask = 0; - dispPtr->altModMask = 0; - codePtr = modMapPtr->modifiermap; - max = 8*modMapPtr->max_keypermod; - for (i = 0; i < max; i++, codePtr++) { - if (*codePtr == 0) { - continue; - } - keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - if (keysym == XK_Mode_switch) { - dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) { - dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) { - dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - } - - /* - * Create an array of the keycodes for all modifier keys. - */ - - if (dispPtr->modKeyCodes != NULL) { - ckfree((char *) dispPtr->modKeyCodes); - } - dispPtr->numModKeyCodes = 0; - arraySize = KEYCODE_ARRAY_SIZE; - dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned) - (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); - for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) { - if (*codePtr == 0) { - continue; - } - - /* - * Make sure that the keycode isn't already in the array. - */ - - for (j = 0; j < dispPtr->numModKeyCodes; j++) { - if (dispPtr->modKeyCodes[j] == *codePtr) { - goto nextModCode; - } - } - if (dispPtr->numModKeyCodes >= arraySize) { - KeyCode *new; - - /* - * Ran out of space in the array; grow it. - */ - - arraySize *= 2; - new = (KeyCode *) ckalloc((unsigned) - (arraySize * sizeof(KeyCode))); - memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes, - (dispPtr->numModKeyCodes * sizeof(KeyCode))); - ckfree((char *) dispPtr->modKeyCodes); - dispPtr->modKeyCodes = new; - } - dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr; - dispPtr->numModKeyCodes++; - nextModCode: continue; - } - XFreeModifiermap(modMapPtr); -} - -/* - *--------------------------------------------------------------------------- - * - * EvalTclBinding -- - * - * The procedure that is invoked by Tk_BindEvent when a Tcl binding - * is fired. - * - * Results: - * A standard Tcl result code, the result of globally evaluating the - * percent-substitued binding string. - * - * Side effects: - * Normal side effects due to eval. - * - *--------------------------------------------------------------------------- - */ - -static void -FreeTclBinding(clientData) - ClientData clientData; -{ - ckfree((char *) clientData); -} - -/* - *---------------------------------------------------------------------- - * - * TkStringToKeysym -- - * - * This procedure finds the keysym associated with a given keysym - * name. - * - * Results: - * The return value is the keysym that corresponds to name, or - * NoSymbol if there is no such keysym. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -KeySym -TkStringToKeysym(name) - char *name; /* Name of a keysym. */ -{ -#ifdef REDO_KEYSYM_LOOKUP - Tcl_HashEntry *hPtr; - KeySym keysym; - - hPtr = Tcl_FindHashEntry(&keySymTable, name); - if (hPtr != NULL) { - return (KeySym) Tcl_GetHashValue(hPtr); - } - if (strlen(name) == 1) { - keysym = (KeySym) (unsigned char) name[0]; - if (TkKeysymToString(keysym) != NULL) { - return keysym; - } - } -#endif /* REDO_KEYSYM_LOOKUP */ - return XStringToKeysym(name); -} - -/* - *---------------------------------------------------------------------- - * - * TkKeysymToString -- - * - * This procedure finds the keysym name associated with a given - * keysym. - * - * Results: - * The return value is a pointer to a static string containing - * the name of the given keysym, or NULL if there is no known name. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -TkKeysymToString(keysym) - KeySym keysym; -{ -#ifdef REDO_KEYSYM_LOOKUP - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&nameTable, (char *)keysym); - if (hPtr != NULL) { - return (char *) Tcl_GetHashValue(hPtr); - } -#endif /* REDO_KEYSYM_LOOKUP */ - return XKeysymToString(keysym); -} - -/* - *---------------------------------------------------------------------- - * - * TkCopyAndGlobalEval -- - * - * This procedure makes a copy of a script then calls Tcl_GlobalEval - * to evaluate it. It's used in situations where the execution of - * a command may cause the original command string to be reallocated. - * - * Results: - * Returns the result of evaluating script, including both a standard - * Tcl completion code and a string in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkCopyAndGlobalEval(interp, script) - Tcl_Interp *interp; /* Interpreter in which to evaluate - * script. */ - char *script; /* Script to evaluate. */ -{ - Tcl_DString buffer; - int code; - - Tcl_DStringInit(&buffer); - Tcl_DStringAppend(&buffer, script, -1); - code = Tcl_GlobalEval(interp, Tcl_DStringValue(&buffer)); - Tcl_DStringFree(&buffer); - return code; -} - - diff --git a/generic/tkBitmap.c b/generic/tkBitmap.c deleted file mode 100644 index e7a14b9..0000000 --- a/generic/tkBitmap.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * tkBitmap.c -- - * - * This file maintains a database of read-only bitmaps for the Tk - * toolkit. This allows bitmaps to be shared between widgets and - * also avoids interactions with the X server. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkBitmap.c,v 1.6 1998/09/14 18:23:03 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * The includes below are for pre-defined bitmaps. - * - * Platform-specific issue: Windows complains when the bitmaps are - * included, because an array of characters is being initialized with - * integers as elements. For lint purposes, the following pragmas - * temporarily turn off that warning message. - */ - -#if defined(__WIN32__) || defined(_WIN32) -#pragma warning (disable : 4305) -#endif - -#include "error.bmp" -#include "gray12.bmp" -#include "gray25.bmp" -#include "gray50.bmp" -#include "gray75.bmp" -#include "hourglass.bmp" -#include "info.bmp" -#include "questhead.bmp" -#include "question.bmp" -#include "warning.bmp" - -#if defined(__WIN32__) || defined(_WIN32) -#pragma warning (default : 4305) -#endif - -/* - * One of the following data structures exists for each bitmap that is - * currently in use. Each structure is indexed with both "idTable" and - * "nameTable". - */ - -typedef struct { - Pixmap bitmap; /* X identifier for bitmap. None means this - * bitmap was created by Tk_DefineBitmap - * and it isn't currently in use. */ - int width, height; /* Dimensions of bitmap. */ - Display *display; /* Display for which bitmap is valid. */ - int refCount; /* Number of active uses of bitmap. */ - Tcl_HashEntry *hashPtr; /* Entry in nameTable for this structure - * (needed when deleting). */ -} TkBitmap; - -/* - * Hash table to map from a textual description of a bitmap to the - * TkBitmap record for the bitmap, and key structure used in that - * hash table: - */ - -static Tcl_HashTable nameTable; -typedef struct { - Tk_Uid name; /* Textual name for desired bitmap. */ - Screen *screen; /* Screen on which bitmap will be used. */ -} NameKey; - -/* - * Hash table that maps from <display + bitmap id> to the TkBitmap structure - * for the bitmap. This table is used by Tk_FreeBitmap. - */ - -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which bitmap was allocated. */ - Pixmap pixmap; /* X identifier for pixmap. */ -} IdKey; - -/* - * Hash table create by Tk_DefineBitmap to map from a name to a - * collection of in-core data about a bitmap. The table is - * indexed by the address of the data for the bitmap, and the entries - * contain pointers to TkPredefBitmap structures. - */ - -Tcl_HashTable tkPredefBitmapTable; - -/* - * Hash table used by Tk_GetBitmapFromData to map from a collection - * of in-core data about a bitmap to a Tk_Uid giving an automatically- - * generated name for the bitmap: - */ - -static Tcl_HashTable dataTable; -typedef struct { - char *source; /* Bitmap bits. */ - int width, height; /* Dimensions of bitmap. */ -} DataKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static void BitmapInit _ANSI_ARGS_((void)); - -/* - *---------------------------------------------------------------------- - * - * Tk_GetBitmap -- - * - * Given a string describing a bitmap, locate (or create if necessary) - * a bitmap that fits the description. - * - * Results: - * The return value is the X identifer for the desired bitmap - * (i.e. a Pixmap with a single plane), unless string couldn't be - * parsed correctly. In this case, None is returned and an error - * message is left in interp->result. The caller should never - * modify the bitmap that is returned, and should eventually call - * Tk_FreeBitmap when the bitmap is no longer needed. - * - * Side effects: - * The bitmap is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps - * aren't needed anymore. - * - *---------------------------------------------------------------------- - */ - -Pixmap -Tk_GetBitmap(interp, tkwin, string) - Tcl_Interp *interp; /* Interpreter to use for error reporting, - * this may be NULL. */ - Tk_Window tkwin; /* Window in which bitmap will be used. */ - Tk_Uid string; /* Description of bitmap. See manual entry - * for details on legal syntax. */ -{ - NameKey nameKey; - IdKey idKey; - Tcl_HashEntry *nameHashPtr, *idHashPtr, *predefHashPtr; - register TkBitmap *bitmapPtr; - TkPredefBitmap *predefPtr; - int new; - Pixmap bitmap; - int width, height; - int dummy2; - - if (!initialized) { - BitmapInit(); - } - - nameKey.name = string; - nameKey.screen = Tk_Screen(tkwin); - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); - if (!new) { - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); - bitmapPtr->refCount++; - return bitmapPtr->bitmap; - } - - /* - * No suitable bitmap exists. Create a new bitmap from the - * information contained in the string. If the string starts - * with "@" then the rest of the string is a file name containing - * the bitmap. Otherwise the string must refer to a bitmap - * defined by a call to Tk_DefineBitmap. - */ - - if (*string == '@') { - Tcl_DString buffer; - int result; - - if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't specify bitmap with '@' in a", - " safe interpreter", (char *) NULL); - goto error; - } - - string = Tcl_TranslateFileName(interp, string + 1, &buffer); - if (string == NULL) { - goto error; - } - result = TkReadBitmapFile(Tk_Display(tkwin), - RootWindowOfScreen(nameKey.screen), string, - (unsigned int *) &width, (unsigned int *) &height, - &bitmap, &dummy2, &dummy2); - if (result != BitmapSuccess) { - if (interp != NULL) { - Tcl_AppendResult(interp, "error reading bitmap file \"", string, - "\"", (char *) NULL); - } - Tcl_DStringFree(&buffer); - goto error; - } - Tcl_DStringFree(&buffer); - } else { - predefHashPtr = Tcl_FindHashEntry(&tkPredefBitmapTable, string); - if (predefHashPtr == NULL) { - /* - * The following platform specific call allows the user to - * define bitmaps that may only exist during run time. If - * it returns None nothing was found and we return the error. - */ - bitmap = TkpGetNativeAppBitmap(Tk_Display(tkwin), string, - &width, &height); - - if (bitmap == None) { - if (interp != NULL) { - Tcl_AppendResult(interp, "bitmap \"", string, - "\" not defined", (char *) NULL); - } - goto error; - } - } else { - predefPtr = (TkPredefBitmap *) Tcl_GetHashValue(predefHashPtr); - width = predefPtr->width; - height = predefPtr->height; - if (predefPtr->native) { - bitmap = TkpCreateNativeBitmap(Tk_Display(tkwin), - predefPtr->source); - if (bitmap == None) { - panic("native bitmap creation failed"); - } - } else { - bitmap = XCreateBitmapFromData(Tk_Display(tkwin), - RootWindowOfScreen(nameKey.screen), predefPtr->source, - (unsigned) width, (unsigned) height); - } - } - } - - /* - * Add information about this bitmap to our database. - */ - - bitmapPtr = (TkBitmap *) ckalloc(sizeof(TkBitmap)); - bitmapPtr->bitmap = bitmap; - bitmapPtr->width = width; - bitmapPtr->height = height; - bitmapPtr->display = Tk_Display(tkwin); - bitmapPtr->refCount = 1; - bitmapPtr->hashPtr = nameHashPtr; - idKey.display = bitmapPtr->display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, - &new); - if (!new) { - panic("bitmap already registered in Tk_GetBitmap"); - } - Tcl_SetHashValue(nameHashPtr, bitmapPtr); - Tcl_SetHashValue(idHashPtr, bitmapPtr); - return bitmapPtr->bitmap; - - error: - Tcl_DeleteHashEntry(nameHashPtr); - return None; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DefineBitmap -- - * - * This procedure associates a textual name with a binary bitmap - * description, so that the name may be used to refer to the - * bitmap in future calls to Tk_GetBitmap. - * - * Results: - * A standard Tcl result. If an error occurs then TCL_ERROR is - * returned and a message is left in interp->result. - * - * Side effects: - * "Name" is entered into the bitmap table and may be used from - * here on to refer to the given bitmap. - * - *---------------------------------------------------------------------- - */ - -int -Tk_DefineBitmap(interp, name, source, width, height) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Uid name; /* Name to use for bitmap. Must not already - * be defined as a bitmap. */ - char *source; /* Address of bits for bitmap. */ - int width; /* Width of bitmap. */ - int height; /* Height of bitmap. */ -{ - int new; - Tcl_HashEntry *predefHashPtr; - TkPredefBitmap *predefPtr; - - if (!initialized) { - BitmapInit(); - } - - predefHashPtr = Tcl_CreateHashEntry(&tkPredefBitmapTable, name, &new); - if (!new) { - Tcl_AppendResult(interp, "bitmap \"", name, - "\" is already defined", (char *) NULL); - return TCL_ERROR; - } - predefPtr = (TkPredefBitmap *) ckalloc(sizeof(TkPredefBitmap)); - predefPtr->source = source; - predefPtr->width = width; - predefPtr->height = height; - predefPtr->native = 0; - Tcl_SetHashValue(predefHashPtr, predefPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfBitmap -- - * - * Given a bitmap, return a textual string identifying the - * bitmap. - * - * Results: - * The return value is the string name associated with bitmap. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -Tk_Uid -Tk_NameOfBitmap(display, bitmap) - Display *display; /* Display for which bitmap was - * allocated. */ - Pixmap bitmap; /* Bitmap whose name is wanted. */ -{ - IdKey idKey; - Tcl_HashEntry *idHashPtr; - TkBitmap *bitmapPtr; - - if (!initialized) { - unknown: - panic("Tk_NameOfBitmap received unknown bitmap argument"); - } - - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - goto unknown; - } - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); - return ((NameKey *) bitmapPtr->hashPtr->key.words)->name; -} - -/* - *-------------------------------------------------------------- - * - * Tk_SizeOfBitmap -- - * - * Given a bitmap managed by this module, returns the width - * and height of the bitmap. - * - * Results: - * The words at *widthPtr and *heightPtr are filled in with - * the dimenstions of bitmap. - * - * Side effects: - * If bitmap isn't managed by this module then the procedure - * panics.. - * - *-------------------------------------------------------------- - */ - -void -Tk_SizeOfBitmap(display, bitmap, widthPtr, heightPtr) - Display *display; /* Display for which bitmap was - * allocated. */ - Pixmap bitmap; /* Bitmap whose size is wanted. */ - int *widthPtr; /* Store bitmap width here. */ - int *heightPtr; /* Store bitmap height here. */ -{ - IdKey idKey; - Tcl_HashEntry *idHashPtr; - TkBitmap *bitmapPtr; - - if (!initialized) { - unknownBitmap: - panic("Tk_SizeOfBitmap received unknown bitmap argument"); - } - - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - goto unknownBitmap; - } - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); - *widthPtr = bitmapPtr->width; - *heightPtr = bitmapPtr->height; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeBitmap -- - * - * This procedure is called to release a bitmap allocated by - * Tk_GetBitmap or TkGetBitmapFromData. - * - * Results: - * None. - * - * Side effects: - * The reference count associated with bitmap is decremented, and - * it is officially deallocated if no-one is using it anymore. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeBitmap(display, bitmap) - Display *display; /* Display for which bitmap was - * allocated. */ - Pixmap bitmap; /* Bitmap to be released. */ -{ - Tcl_HashEntry *idHashPtr; - register TkBitmap *bitmapPtr; - IdKey idKey; - - if (!initialized) { - panic("Tk_FreeBitmap called before Tk_GetBitmap"); - } - - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - panic("Tk_FreeBitmap received unknown bitmap argument"); - } - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); - bitmapPtr->refCount--; - if (bitmapPtr->refCount == 0) { - Tk_FreePixmap(bitmapPtr->display, bitmapPtr->bitmap); - Tcl_DeleteHashEntry(idHashPtr); - Tcl_DeleteHashEntry(bitmapPtr->hashPtr); - ckfree((char *) bitmapPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetBitmapFromData -- - * - * Given a description of the bits for a bitmap, make a bitmap that - * has the given properties. *** NOTE: this procedure is obsolete - * and really shouldn't be used anymore. *** - * - * Results: - * The return value is the X identifer for the desired bitmap - * (a one-plane Pixmap), unless it couldn't be created properly. - * In this case, None is returned and an error message is left in - * interp->result. The caller should never modify the bitmap that - * is returned, and should eventually call Tk_FreeBitmap when the - * bitmap is no longer needed. - * - * Side effects: - * The bitmap is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps - * aren't needed anymore. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -Pixmap -Tk_GetBitmapFromData(interp, tkwin, source, width, height) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Window tkwin; /* Window in which bitmap will be used. */ - char *source; /* Bitmap data for bitmap shape. */ - int width, height; /* Dimensions of bitmap. */ -{ - DataKey nameKey; - Tcl_HashEntry *dataHashPtr; - Tk_Uid name; - int new; - char string[20]; - static int autoNumber = 0; - - if (!initialized) { - BitmapInit(); - } - - nameKey.source = source; - nameKey.width = width; - nameKey.height = height; - dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &nameKey, &new); - if (!new) { - name = (Tk_Uid) Tcl_GetHashValue(dataHashPtr); - } else { - autoNumber++; - sprintf(string, "_tk%d", autoNumber); - name = Tk_GetUid(string); - Tcl_SetHashValue(dataHashPtr, name); - if (Tk_DefineBitmap(interp, name, source, width, height) != TCL_OK) { - Tcl_DeleteHashEntry(dataHashPtr); - return TCL_ERROR; - } - } - return Tk_GetBitmap(interp, tkwin, name); -} - -/* - *---------------------------------------------------------------------- - * - * BitmapInit -- - * - * Initialize the structures used for bitmap management. - * - * Results: - * None. - * - * Side effects: - * Read the code. - * - *---------------------------------------------------------------------- - */ - -static void -BitmapInit() -{ - Tcl_Interp *dummy; - - dummy = Tcl_CreateInterp(); - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); - Tcl_InitHashTable(&tkPredefBitmapTable, TCL_ONE_WORD_KEYS); - - /* - * The call below is tricky: can't use sizeof(IdKey) because it - * gets padded with extra unpredictable bytes on some 64-bit - * machines. - */ - - Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Pixmap)) - /sizeof(int)); - - Tk_DefineBitmap(dummy, Tk_GetUid("error"), (char *) error_bits, - error_width, error_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray75"), (char *) gray75_bits, - gray75_width, gray75_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray50"), (char *) gray50_bits, - gray50_width, gray50_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray25"), (char *) gray25_bits, - gray25_width, gray25_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray12"), (char *) gray12_bits, - gray12_width, gray12_height); - Tk_DefineBitmap(dummy, Tk_GetUid("hourglass"), (char *) hourglass_bits, - hourglass_width, hourglass_height); - Tk_DefineBitmap(dummy, Tk_GetUid("info"), (char *) info_bits, - info_width, info_height); - Tk_DefineBitmap(dummy, Tk_GetUid("questhead"), (char *) questhead_bits, - questhead_width, questhead_height); - Tk_DefineBitmap(dummy, Tk_GetUid("question"), (char *) question_bits, - question_width, question_height); - Tk_DefineBitmap(dummy, Tk_GetUid("warning"), (char *) warning_bits, - warning_width, warning_height); - - TkpDefineNativeBitmaps(); - - Tcl_DeleteInterp(dummy); -} - -/* - *---------------------------------------------------------------------- - * - * TkReadBitmapFile -- - * - * Loads a bitmap image in X bitmap format into the specified - * drawable. This is equivelent to the XReadBitmapFile in X. - * - * Results: - * Sets the size, hotspot, and bitmap on success. - * - * Side effects: - * Creates a new bitmap from the file data. - * - *---------------------------------------------------------------------- - */ - -int -TkReadBitmapFile(display, d, filename, width_return, height_return, - bitmap_return, x_hot_return, y_hot_return) - Display* display; - Drawable d; - CONST char* filename; - unsigned int* width_return; - unsigned int* height_return; - Pixmap* bitmap_return; - int* x_hot_return; - int* y_hot_return; -{ - char *data; - - data = TkGetBitmapData(NULL, NULL, (char *) filename, - (int *) width_return, (int *) height_return, x_hot_return, - y_hot_return); - if (data == NULL) { - return BitmapFileInvalid; - } - - *bitmap_return = XCreateBitmapFromData(display, d, data, *width_return, - *height_return); - - ckfree(data); - return BitmapSuccess; -} diff --git a/generic/tkButton.c b/generic/tkButton.c deleted file mode 100644 index aea1e58..0000000 --- a/generic/tkButton.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * tkButton.c -- - * - * This module implements a collection of button-like - * widgets for the Tk toolkit. The widgets implemented - * include labels, buttons, check buttons, and radio - * buttons. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkButton.c,v 1.2 1998/09/14 18:23:04 stanton Exp $ - */ - -#include "tkButton.h" -#include "default.h" - -/* - * Class names for buttons, indexed by one of the type values above. - */ - -static char *classNames[] = {"Label", "Button", "Checkbutton", "Radiobutton"}; - -/* - * The class procedure table for the button widget. - */ - -static int configFlags[] = {LABEL_MASK, BUTTON_MASK, - CHECK_BUTTON_MASK, RADIO_BUTTON_MASK}; - -/* - * Information used for parsing configuration specs: - */ - -Tk_ConfigSpec tkpButtonConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_BUTTON_ACTIVE_BG_COLOR, Tk_Offset(TkButton, activeBorder), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(TkButton, activeBorder), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_BUTTON_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg), - BUTTON_MASK|TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_CHKRAD_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(TkButton, activeFg), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", - DEF_BUTTON_ANCHOR, Tk_Offset(TkButton, anchor), ALL_MASK}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_BUTTON_BG_COLOR, Tk_Offset(TkButton, normalBorder), - ALL_MASK | TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_BUTTON_BG_MONO, Tk_Offset(TkButton, normalBorder), - ALL_MASK | TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", - DEF_BUTTON_BITMAP, Tk_Offset(TkButton, bitmap), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidth), ALL_MASK}, - {TK_CONFIG_STRING, "-command", "command", "Command", - DEF_BUTTON_COMMAND, Tk_Offset(TkButton, command), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_BUTTON_CURSOR, Tk_Offset(TkButton, cursor), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-default", "default", "Default", - DEF_BUTTON_DEFAULT, Tk_Offset(TkButton, defaultState), BUTTON_MASK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, - Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_BUTTON_DISABLED_FG_MONO, - Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_BUTTON_FONT, Tk_Offset(TkButton, tkfont), - ALL_MASK}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_BUTTON_FG, Tk_Offset(TkButton, normalFg), LABEL_MASK|BUTTON_MASK}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_CHKRAD_FG, Tk_Offset(TkButton, normalFg), CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-height", "height", "Height", - DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightString), ALL_MASK}, - {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG, - Tk_Offset(TkButton, highlightBorder), ALL_MASK}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_BUTTON_HIGHLIGHT, Tk_Offset(TkButton, highlightColorPtr), - ALL_MASK}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_LABEL_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth), - LABEL_MASK}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_BUTTON_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-image", "image", "Image", - DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imageString), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", - DEF_BUTTON_INDICATOR, Tk_Offset(TkButton, indicatorOn), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_BUTTON_JUSTIFY, Tk_Offset(TkButton, justify), ALL_MASK}, - {TK_CONFIG_STRING, "-offvalue", "offValue", "Value", - DEF_BUTTON_OFF_VALUE, Tk_Offset(TkButton, offValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_STRING, "-onvalue", "onValue", "Value", - DEF_BUTTON_ON_VALUE, Tk_Offset(TkButton, onValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_BUTTON_PADX, Tk_Offset(TkButton, padX), BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padX), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_BUTTON_PADY, Tk_Offset(TkButton, padY), BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padY), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_BUTTON_RELIEF, Tk_Offset(TkButton, relief), BUTTON_MASK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_LABCHKRAD_RELIEF, Tk_Offset(TkButton, relief), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", - DEF_BUTTON_SELECT_COLOR, Tk_Offset(TkButton, selectBorder), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", - DEF_BUTTON_SELECT_MONO, Tk_Offset(TkButton, selectBorder), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-selectimage", "selectImage", "SelectImage", - DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImageString), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_BUTTON_STATE, Tk_Offset(TkButton, state), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_LABEL_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus), - LABEL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-text", "text", "Text", - DEF_BUTTON_TEXT, Tk_Offset(TkButton, text), ALL_MASK}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarName), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-underline", "underline", "Underline", - DEF_BUTTON_UNDERLINE, Tk_Offset(TkButton, underline), ALL_MASK}, - {TK_CONFIG_STRING, "-value", "value", "Value", - DEF_BUTTON_VALUE, Tk_Offset(TkButton, onValue), - RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_RADIOBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName), - RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_CHECKBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName), - CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-width", "width", "Width", - DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthString), ALL_MASK}, - {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", - DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLength), ALL_MASK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * String to print out in error messages, identifying options for - * widget commands for different types of labels or buttons: - */ - -static char *optionStrings[] = { - "cget or configure", - "cget, configure, flash, or invoke", - "cget, configure, deselect, flash, invoke, select, or toggle", - "cget, configure, deselect, flash, invoke, or select" -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void ButtonCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static int ButtonCreate _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv, - int type)); -static void ButtonEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void ButtonImageProc _ANSI_ARGS_((ClientData clientData, - int x, int y, int width, int height, - int imgWidth, int imgHeight)); -static void ButtonSelectImageProc _ANSI_ARGS_(( - ClientData clientData, int x, int y, int width, - int height, int imgWidth, int imgHeight)); -static char * ButtonTextVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static char * ButtonVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static int ButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static int ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp, - TkButton *butPtr, int argc, char **argv, - int flags)); -static void DestroyButton _ANSI_ARGS_((TkButton *butPtr)); - - -/* - *-------------------------------------------------------------- - * - * Tk_ButtonCmd, Tk_CheckbuttonCmd, Tk_LabelCmd, Tk_RadiobuttonCmd -- - * - * These procedures are invoked to process the "button", "label", - * "radiobutton", and "checkbutton" Tcl commands. See the - * user documentation for details on what they do. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. These procedures are just wrappers; - * they call ButtonCreate to do all of the real work. - * - *-------------------------------------------------------------- - */ - -int -Tk_ButtonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return ButtonCreate(clientData, interp, argc, argv, TYPE_BUTTON); -} - -int -Tk_CheckbuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return ButtonCreate(clientData, interp, argc, argv, TYPE_CHECK_BUTTON); -} - -int -Tk_LabelCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return ButtonCreate(clientData, interp, argc, argv, TYPE_LABEL); -} - -int -Tk_RadiobuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return ButtonCreate(clientData, interp, argc, argv, TYPE_RADIO_BUTTON); -} - -/* - *-------------------------------------------------------------- - * - * ButtonCreate -- - * - * This procedure does all the real work of implementing the - * "button", "label", "radiobutton", and "checkbutton" Tcl - * commands. See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ButtonCreate(clientData, interp, argc, argv, type) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ - int type; /* Type of button to create: TYPE_LABEL, - * TYPE_BUTTON, TYPE_CHECK_BUTTON, or - * TYPE_RADIO_BUTTON. */ -{ - register TkButton *butPtr; - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Create the new window. - */ - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - Tk_SetClass(new, classNames[type]); - butPtr = TkpCreateButton(new); - - TkSetClassProcs(new, &tkpButtonProcs, (ClientData) butPtr); - - /* - * Initialize the data structure for the button. - */ - - butPtr->tkwin = new; - butPtr->display = Tk_Display(new); - butPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(butPtr->tkwin), - ButtonWidgetCmd, (ClientData) butPtr, ButtonCmdDeletedProc); - butPtr->interp = interp; - butPtr->type = type; - butPtr->text = NULL; - butPtr->underline = -1; - butPtr->textVarName = NULL; - butPtr->bitmap = None; - butPtr->imageString = NULL; - butPtr->image = NULL; - butPtr->selectImageString = NULL; - butPtr->selectImage = NULL; - butPtr->state = tkNormalUid; - butPtr->normalBorder = NULL; - butPtr->activeBorder = NULL; - butPtr->borderWidth = 0; - butPtr->relief = TK_RELIEF_FLAT; - butPtr->highlightWidth = 0; - butPtr->highlightBorder = NULL; - butPtr->highlightColorPtr = NULL; - butPtr->inset = 0; - butPtr->tkfont = NULL; - butPtr->normalFg = NULL; - butPtr->activeFg = NULL; - butPtr->disabledFg = NULL; - butPtr->normalTextGC = None; - butPtr->activeTextGC = None; - butPtr->gray = None; - butPtr->disabledGC = None; - butPtr->copyGC = None; - butPtr->widthString = NULL; - butPtr->heightString = NULL; - butPtr->width = 0; - butPtr->height = 0; - butPtr->wrapLength = 0; - butPtr->padX = 0; - butPtr->padY = 0; - butPtr->anchor = TK_ANCHOR_CENTER; - butPtr->justify = TK_JUSTIFY_CENTER; - butPtr->textLayout = NULL; - butPtr->indicatorOn = 0; - butPtr->selectBorder = NULL; - butPtr->indicatorSpace = 0; - butPtr->indicatorDiameter = 0; - butPtr->defaultState = tkDisabledUid; - butPtr->selVarName = NULL; - butPtr->onValue = NULL; - butPtr->offValue = NULL; - butPtr->cursor = None; - butPtr->command = NULL; - butPtr->takeFocus = NULL; - butPtr->flags = 0; - - Tk_CreateEventHandler(butPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - ButtonEventProc, (ClientData) butPtr); - - if (ConfigureButton(interp, butPtr, argc - 2, argv + 2, - configFlags[type]) != TCL_OK) { - Tk_DestroyWindow(butPtr->tkwin); - return TCL_ERROR; - } - - interp->result = Tk_PathName(butPtr->tkwin); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ButtonWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ButtonWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about button widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkButton *butPtr = (TkButton *) clientData; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) butPtr); - c = argv[1][0]; - length = strlen(argv[1]); - - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, butPtr->tkwin, tkpButtonConfigSpecs, - (char *) butPtr, argv[2], configFlags[butPtr->type]); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, butPtr->tkwin, - tkpButtonConfigSpecs, (char *) butPtr, (char *) NULL, - configFlags[butPtr->type]); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, butPtr->tkwin, - tkpButtonConfigSpecs, (char *) butPtr, argv[2], - configFlags[butPtr->type]); - } else { - result = ConfigureButton(interp, butPtr, argc-2, argv+2, - configFlags[butPtr->type] | TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "deselect", length) == 0) - && (butPtr->type >= TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s deselect\"", - argv[0]); - goto error; - } - if (butPtr->type == TYPE_CHECK_BUTTON) { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } else if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(interp, butPtr->selVarName, "", - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - }; - } - } else if ((c == 'f') && (strncmp(argv[1], "flash", length) == 0) - && (butPtr->type != TYPE_LABEL)) { - int i; - - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s flash\"", - argv[0]); - goto error; - } - if (butPtr->state != tkDisabledUid) { - for (i = 0; i < 4; i++) { - butPtr->state = (butPtr->state == tkNormalUid) - ? tkActiveUid : tkNormalUid; - Tk_SetBackgroundFromBorder(butPtr->tkwin, - (butPtr->state == tkActiveUid) ? butPtr->activeBorder - : butPtr->normalBorder); - TkpDisplayButton((ClientData) butPtr); - - /* - * Special note: must cancel any existing idle handler - * for TkpDisplayButton; it's no longer needed, and TkpDisplayButton - * cleared the REDRAW_PENDING flag. - */ - - Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); - XFlush(butPtr->display); - Tcl_Sleep(50); - } - } - } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) - && (butPtr->type > TYPE_LABEL)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s invoke\"", - argv[0]); - goto error; - } - if (butPtr->state != tkDisabledUid) { - result = TkInvokeButton(butPtr); - } - } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) - && (butPtr->type >= TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s select\"", - argv[0]); - goto error; - } - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } else if ((c == 't') && (strncmp(argv[1], "toggle", length) == 0) - && (length >= 2) && (butPtr->type == TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s toggle\"", - argv[0]); - goto error; - } - if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } else { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } - } else { - sprintf(interp->result, - "bad option \"%.50s\": must be %s", argv[1], - optionStrings[butPtr->type]); - goto error; - } - Tcl_Release((ClientData) butPtr); - return result; - - error: - Tcl_Release((ClientData) butPtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyButton -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a button at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the widget is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyButton(butPtr) - TkButton *butPtr; /* Info about button widget. */ -{ - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (butPtr->textVarName != NULL) { - Tcl_UntraceVar(butPtr->interp, butPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonTextVarProc, (ClientData) butPtr); - } - if (butPtr->image != NULL) { - Tk_FreeImage(butPtr->image); - } - if (butPtr->selectImage != NULL) { - Tk_FreeImage(butPtr->selectImage); - } - if (butPtr->normalTextGC != None) { - Tk_FreeGC(butPtr->display, butPtr->normalTextGC); - } - if (butPtr->activeTextGC != None) { - Tk_FreeGC(butPtr->display, butPtr->activeTextGC); - } - if (butPtr->gray != None) { - Tk_FreeBitmap(butPtr->display, butPtr->gray); - } - if (butPtr->disabledGC != None) { - Tk_FreeGC(butPtr->display, butPtr->disabledGC); - } - if (butPtr->copyGC != None) { - Tk_FreeGC(butPtr->display, butPtr->copyGC); - } - if (butPtr->selVarName != NULL) { - Tcl_UntraceVar(butPtr->interp, butPtr->selVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonVarProc, (ClientData) butPtr); - } - Tk_FreeTextLayout(butPtr->textLayout); - Tk_FreeOptions(tkpButtonConfigSpecs, (char *) butPtr, butPtr->display, - configFlags[butPtr->type]); - Tcl_EventuallyFree((ClientData)butPtr, TCL_DYNAMIC); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureButton -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a button widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for butPtr; old resources get freed, if there - * were any. The button is redisplayed. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureButton(interp, butPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkButton *butPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - Tk_Image image; - - /* - * Eliminate any existing trace on variables monitored by the button. - */ - - if (butPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, butPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonTextVarProc, (ClientData) butPtr); - } - if (butPtr->selVarName != NULL) { - Tcl_UntraceVar(interp, butPtr->selVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonVarProc, (ClientData) butPtr); - } - - - - if (Tk_ConfigureWidget(interp, butPtr->tkwin, tkpButtonConfigSpecs, - argc, argv, (char *) butPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few options need special processing, such as setting the - * background from a 3-D border, or filling in complicated - * defaults that couldn't be specified to Tk_ConfigureWidget. - */ - - if ((butPtr->state == tkActiveUid) && !Tk_StrictMotif(butPtr->tkwin)) { - Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); - } else { - Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); - if ((butPtr->state != tkNormalUid) && (butPtr->state != tkActiveUid) - && (butPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", butPtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - butPtr->state = tkNormalUid; - return TCL_ERROR; - } - } - - if ((butPtr->defaultState != tkActiveUid) - && (butPtr->defaultState != tkDisabledUid) - && (butPtr->defaultState != tkNormalUid)) { - Tcl_AppendResult(interp, "bad -default value \"", butPtr->defaultState, - "\": must be normal, active, or disabled", (char *) NULL); - butPtr->defaultState = tkDisabledUid; - return TCL_ERROR; - } - - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; - } - - if (butPtr->padX < 0) { - butPtr->padX = 0; - } - if (butPtr->padY < 0) { - butPtr->padY = 0; - } - - if (butPtr->type >= TYPE_CHECK_BUTTON) { - char *value; - - if (butPtr->selVarName == NULL) { - butPtr->selVarName = (char *) ckalloc((unsigned) - (strlen(Tk_Name(butPtr->tkwin)) + 1)); - strcpy(butPtr->selVarName, Tk_Name(butPtr->tkwin)); - } - - /* - * Select the button if the associated variable has the - * appropriate value, initialize the variable if it doesn't - * exist, then set a trace on the variable to monitor future - * changes to its value. - */ - - value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); - butPtr->flags &= ~SELECTED; - if (value != NULL) { - if (strcmp(value, butPtr->onValue) == 0) { - butPtr->flags |= SELECTED; - } - } else { - if (Tcl_SetVar(interp, butPtr->selVarName, - (butPtr->type == TYPE_CHECK_BUTTON) ? butPtr->offValue : "", - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; - } - } - Tcl_TraceVar(interp, butPtr->selVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonVarProc, (ClientData) butPtr); - } - - /* - * Get the images for the widget, if there are any. Allocate the - * new images before freeing the old ones, so that the reference - * counts don't go to zero and cause image data to be discarded. - */ - - if (butPtr->imageString != NULL) { - image = Tk_GetImage(butPtr->interp, butPtr->tkwin, - butPtr->imageString, ButtonImageProc, (ClientData) butPtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (butPtr->image != NULL) { - Tk_FreeImage(butPtr->image); - } - butPtr->image = image; - if (butPtr->selectImageString != NULL) { - image = Tk_GetImage(butPtr->interp, butPtr->tkwin, - butPtr->selectImageString, ButtonSelectImageProc, - (ClientData) butPtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (butPtr->selectImage != NULL) { - Tk_FreeImage(butPtr->selectImage); - } - butPtr->selectImage = image; - - if ((butPtr->image == NULL) && (butPtr->bitmap == None) - && (butPtr->textVarName != NULL)) { - /* - * The button must display the value of a variable: set up a trace - * on the variable's value, create the variable if it doesn't - * exist, and fetch its current value. - */ - - char *value; - - value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - if (Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; - } - } else { - if (butPtr->text != NULL) { - ckfree(butPtr->text); - } - butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(butPtr->text, value); - } - Tcl_TraceVar(interp, butPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonTextVarProc, (ClientData) butPtr); - } - - if ((butPtr->bitmap != None) || (butPtr->image != NULL)) { - if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->widthString, - &butPtr->width) != TCL_OK) { - widthError: - Tcl_AddErrorInfo(interp, "\n (processing -width option)"); - return TCL_ERROR; - } - if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->heightString, - &butPtr->height) != TCL_OK) { - heightError: - Tcl_AddErrorInfo(interp, "\n (processing -height option)"); - return TCL_ERROR; - } - } else { - if (Tcl_GetInt(interp, butPtr->widthString, &butPtr->width) - != TCL_OK) { - goto widthError; - } - if (Tcl_GetInt(interp, butPtr->heightString, &butPtr->height) - != TCL_OK) { - goto heightError; - } - } - - TkButtonWorldChanged((ClientData) butPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * TkButtonWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Button will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -void -TkButtonWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC newGC; - unsigned long mask; - TkButton *butPtr; - - butPtr = (TkButton *) instanceData; - - /* - * Recompute GCs. - */ - - gcValues.font = Tk_FontId(butPtr->tkfont); - gcValues.foreground = butPtr->normalFg->pixel; - gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; - - /* - * Note: GraphicsExpose events are disabled in normalTextGC because it's - * used to copy stuff from an off-screen pixmap onto the screen (we know - * that there's no problem with obscured areas). - */ - - gcValues.graphics_exposures = False; - mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; - newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); - if (butPtr->normalTextGC != None) { - Tk_FreeGC(butPtr->display, butPtr->normalTextGC); - } - butPtr->normalTextGC = newGC; - - if (butPtr->activeFg != NULL) { - gcValues.font = Tk_FontId(butPtr->tkfont); - gcValues.foreground = butPtr->activeFg->pixel; - gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel; - mask = GCForeground | GCBackground | GCFont; - newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); - if (butPtr->activeTextGC != None) { - Tk_FreeGC(butPtr->display, butPtr->activeTextGC); - } - butPtr->activeTextGC = newGC; - } - - if (butPtr->type != TYPE_LABEL) { - gcValues.font = Tk_FontId(butPtr->tkfont); - gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; - if ((butPtr->disabledFg != NULL) && (butPtr->imageString == NULL)) { - gcValues.foreground = butPtr->disabledFg->pixel; - mask = GCForeground | GCBackground | GCFont; - } else { - gcValues.foreground = gcValues.background; - mask = GCForeground; - if (butPtr->gray == None) { - butPtr->gray = Tk_GetBitmap(NULL, butPtr->tkwin, - Tk_GetUid("gray50")); - } - if (butPtr->gray != None) { - gcValues.fill_style = FillStippled; - gcValues.stipple = butPtr->gray; - mask |= GCFillStyle | GCStipple; - } - } - newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); - if (butPtr->disabledGC != None) { - Tk_FreeGC(butPtr->display, butPtr->disabledGC); - } - butPtr->disabledGC = newGC; - } - - if (butPtr->copyGC == None) { - butPtr->copyGC = Tk_GetGC(butPtr->tkwin, 0, &gcValues); - } - - TkpComputeButtonGeometry(butPtr); - - /* - * Lastly, arrange for the button to be redisplayed. - */ - - if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } -} - -/* - *-------------------------------------------------------------- - * - * ButtonEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on buttons. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -ButtonEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkButton *butPtr = (TkButton *) clientData; - if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { - goto redraw; - } else if (eventPtr->type == ConfigureNotify) { - /* - * Must redraw after size changes, since layout could have changed - * and borders will need to be redrawn. - */ - - goto redraw; - } else if (eventPtr->type == DestroyNotify) { - TkpDestroyButton(butPtr); - if (butPtr->tkwin != NULL) { - butPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd); - } - if (butPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); - } - DestroyButton(butPtr); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - butPtr->flags |= GOT_FOCUS; - if (butPtr->highlightWidth > 0) { - goto redraw; - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - butPtr->flags &= ~GOT_FOCUS; - if (butPtr->highlightWidth > 0) { - goto redraw; - } - } - } - return; - - redraw: - if ((butPtr->tkwin != NULL) && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } -} - -/* - *---------------------------------------------------------------------- - * - * ButtonCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -ButtonCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkButton *butPtr = (TkButton *) clientData; - Tk_Window tkwin = butPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - butPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkInvokeButton -- - * - * This procedure is called to carry out the actions associated - * with a button, such as invoking a Tcl command or setting a - * variable. This procedure is invoked, for example, when the - * button is invoked via the mouse. - * - * Results: - * A standard Tcl return value. Information is also left in - * interp->result. - * - * Side effects: - * Depends on the button and its associated command. - * - *---------------------------------------------------------------------- - */ - -int -TkInvokeButton(butPtr) - register TkButton *butPtr; /* Information about button. */ -{ - if (butPtr->type == TYPE_CHECK_BUTTON) { - if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; - } - } else { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; - } - } - } else if (butPtr->type == TYPE_RADIO_BUTTON) { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; - } - } - if ((butPtr->type != TYPE_LABEL) && (butPtr->command != NULL)) { - return TkCopyAndGlobalEval(butPtr->interp, butPtr->command); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ButtonVarProc -- - * - * This procedure is invoked when someone changes the - * state variable associated with a radio button. Depending - * on the new value of the button's variable, the button - * may be selected or deselected. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The button may become selected or deselected. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -ButtonVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about button. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -{ - register TkButton *butPtr = (TkButton *) clientData; - char *value; - - /* - * If the variable is being unset, then just re-establish the - * trace unless the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - butPtr->flags &= ~SELECTED; - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, butPtr->selVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonVarProc, clientData); - } - goto redisplay; - } - - /* - * Use the value of the variable to update the selected status of - * the button. - */ - - value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (strcmp(value, butPtr->onValue) == 0) { - if (butPtr->flags & SELECTED) { - return (char *) NULL; - } - butPtr->flags |= SELECTED; - } else if (butPtr->flags & SELECTED) { - butPtr->flags &= ~SELECTED; - } else { - return (char *) NULL; - } - - redisplay: - if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) - && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } - return (char *) NULL; -} - -/* - *-------------------------------------------------------------- - * - * ButtonTextVarProc -- - * - * This procedure is invoked when someone changes the variable - * whose contents are to be displayed in a button. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The text displayed in the button will change to match the - * variable. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -ButtonTextVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about button. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Not used. */ - char *name2; /* Not used. */ - int flags; /* Information about what happened. */ -{ - register TkButton *butPtr = (TkButton *) clientData; - char *value; - - /* - * If the variable is unset, then immediately recreate it unless - * the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, - TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, butPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonTextVarProc, clientData); - } - return (char *) NULL; - } - - value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (butPtr->text != NULL) { - ckfree(butPtr->text); - } - butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(butPtr->text, value); - TkpComputeButtonGeometry(butPtr); - - if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) - && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } - return (char *) NULL; -} - -/* - *---------------------------------------------------------------------- - * - * ButtonImageProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents - * of an image displayed in a button. - * - * Results: - * None. - * - * Side effects: - * Arranges for the button to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -ButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - register TkButton *butPtr = (TkButton *) clientData; - - if (butPtr->tkwin != NULL) { - TkpComputeButtonGeometry(butPtr); - if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ButtonSelectImageProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents - * of the image displayed in a button when it is selected. - * - * Results: - * None. - * - * Side effects: - * May arrange for the button to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -ButtonSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - register TkButton *butPtr = (TkButton *) clientData; - - /* - * Don't recompute geometry: it's controlled by the primary image. - */ - - if ((butPtr->flags & SELECTED) && (butPtr->tkwin != NULL) - && Tk_IsMapped(butPtr->tkwin) - && !(butPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); - butPtr->flags |= REDRAW_PENDING; - } -} diff --git a/generic/tkButton.h b/generic/tkButton.h deleted file mode 100644 index a873dbe..0000000 --- a/generic/tkButton.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * tkButton.h -- - * - * Declarations of types and functions used to implement - * button-like widgets. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkButton.h,v 1.4 1998/09/14 18:23:04 stanton Exp $ - */ - -#ifndef _TKBUTTON -#define _TKBUTTON - -#ifndef _TKINT -#include "tkInt.h" -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * A data structure of the following type is kept for each - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the button. NULL - * means that the window has been destroyed. */ - Display *display; /* Display containing widget. Needed to - * free up resources after tkwin is gone. */ - Tcl_Interp *interp; /* Interpreter associated with button. */ - Tcl_Command widgetCmd; /* Token for button's widget command. */ - int type; /* Type of widget: restricts operations - * that may be performed on widget. See - * below for possible values. */ - - /* - * Information about what's in the button. - */ - - char *text; /* Text to display in button (malloc'ed) - * or NULL. */ - int underline; /* Index of character to underline. < 0 means - * don't underline anything. */ - char *textVarName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, button displays the contents - * of this variable. */ - Pixmap bitmap; /* Bitmap to display or None. If not None - * then text and textVar are ignored. */ - char *imageString; /* Name of image to display (malloc'ed), or - * NULL. If non-NULL, bitmap, text, and - * textVarName are ignored. */ - Tk_Image image; /* Image to display in window, or NULL if - * none. */ - char *selectImageString; /* Name of image to display when selected - * (malloc'ed), or NULL. */ - Tk_Image selectImage; /* Image to display in window when selected, - * or NULL if none. Ignored if image is - * NULL. */ - - /* - * Information used when displaying widget: - */ - - Tk_Uid state; /* State of button for display purposes: - * normal, active, or disabled. */ - Tk_3DBorder normalBorder; /* Structure used to draw 3-D - * border and background when window - * isn't active. NULL means no such - * border exists. */ - Tk_3DBorder activeBorder; /* Structure used to draw 3-D - * border and background when window - * is active. NULL means no such - * border exists. */ - int borderWidth; /* Width of border. */ - int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - Tk_3DBorder highlightBorder; - /* Structure used to draw 3-D default ring - * and focus highlight area when highlight - * is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *normalFg; /* Foreground color in normal mode. */ - XColor *activeFg; /* Foreground color in active mode. NULL - * means use normalFg instead. */ - XColor *disabledFg; /* Foreground color when disabled. NULL - * means use normalFg with a 50% stipple - * instead. */ - GC normalTextGC; /* GC for drawing text in normal mode. Also - * used to copy from off-screen pixmap onto - * screen. */ - GC activeTextGC; /* GC for drawing text in active mode (NULL - * means use normalTextGC). */ - Pixmap gray; /* Pixmap for displaying disabled text if - * disabledFg is NULL. */ - GC disabledGC; /* Used to produce disabled effect. If - * disabledFg isn't NULL, this GC is used to - * draw button text or icon. Otherwise - * text or icon is drawn with normalGC and - * this GC is used to stipple background - * across it. For labels this is None. */ - GC copyGC; /* Used for copying information from an - * off-screen pixmap to the screen. */ - char *widthString; /* Value of -width option. Malloc'ed. */ - char *heightString; /* Value of -height option. Malloc'ed. */ - int width, height; /* If > 0, these specify dimensions to request - * for window, in characters for text and in - * pixels for bitmaps. In this case the actual - * size of the text string or bitmap is - * ignored in computing desired window size. */ - int wrapLength; /* Line length (in pixels) at which to wrap - * onto next line. <= 0 means don't wrap - * except at newlines. */ - int padX, padY; /* Extra space around text (pixels to leave - * on each side). Ignored for bitmaps and - * images. */ - Tk_Anchor anchor; /* Where text/bitmap should be displayed - * inside button region. */ - Tk_Justify justify; /* Justification to use for multi-line text. */ - int indicatorOn; /* True means draw indicator, false means - * don't draw it. */ - Tk_3DBorder selectBorder; /* For drawing indicator background, or perhaps - * widget background, when selected. */ - int textWidth; /* Width needed to display text as requested, - * in pixels. */ - int textHeight; /* Height needed to display text as requested, - * in pixels. */ - Tk_TextLayout textLayout; /* Saved text layout information. */ - int indicatorSpace; /* Horizontal space (in pixels) allocated for - * display of indicator. */ - int indicatorDiameter; /* Diameter of indicator, in pixels. */ - Tk_Uid defaultState; /* State of default ring: normal, active, or - * disabled. */ - - /* - * For check and radio buttons, the fields below are used - * to manage the variable indicating the button's state. - */ - - char *selVarName; /* Name of variable used to control selected - * state of button. Malloc'ed (if - * not NULL). */ - char *onValue; /* Value to store in variable when - * this button is selected. Malloc'ed (if - * not NULL). */ - char *offValue; /* Value to store in variable when this - * button isn't selected. Malloc'ed - * (if not NULL). Valid only for check - * buttons. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - char *command; /* Command to execute when button is - * invoked; valid for buttons only. - * If not NULL, it's malloc-ed. */ - int flags; /* Various flags; see below for - * definitions. */ -} TkButton; - -/* - * Possible "type" values for buttons. These are the kinds of - * widgets supported by this file. The ordering of the type - * numbers is significant: greater means more features and is - * used in the code. - */ - -#define TYPE_LABEL 0 -#define TYPE_BUTTON 1 -#define TYPE_CHECK_BUTTON 2 -#define TYPE_RADIO_BUTTON 3 - -/* - * Flag bits for buttons: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * SELECTED: Non-zero means this button is selected, - * so special highlight should be drawn. - * GOT_FOCUS: Non-zero means this button currently - * has the input focus. - */ - -#define REDRAW_PENDING 1 -#define SELECTED 2 -#define GOT_FOCUS 4 - -/* - * Mask values used to selectively enable entries in the - * configuration specs: - */ - -#define LABEL_MASK TK_CONFIG_USER_BIT -#define BUTTON_MASK TK_CONFIG_USER_BIT << 1 -#define CHECK_BUTTON_MASK TK_CONFIG_USER_BIT << 2 -#define RADIO_BUTTON_MASK TK_CONFIG_USER_BIT << 3 -#define ALL_MASK (LABEL_MASK | BUTTON_MASK \ - | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK) - -/* - * Declaration of variables shared between the files in the button module. - */ - -extern TkClassProcs tkpButtonProcs; -extern Tk_ConfigSpec tkpButtonConfigSpecs[]; - -/* - * Declaration of procedures used in the implementation of the button - * widget. - */ - -EXTERN void TkButtonWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -EXTERN void TkpComputeButtonGeometry _ANSI_ARGS_(( - TkButton *butPtr)); -EXTERN TkButton * TkpCreateButton _ANSI_ARGS_((Tk_Window tkwin)); -#ifndef TkpDestroyButton -EXTERN void TkpDestroyButton _ANSI_ARGS_((TkButton *butPtr)); -#endif -#ifndef TkpDisplayButton -EXTERN void TkpDisplayButton _ANSI_ARGS_((ClientData clientData)); -#endif -EXTERN int TkInvokeButton _ANSI_ARGS_((TkButton *butPtr)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKBUTTON */ diff --git a/generic/tkCanvArc.c b/generic/tkCanvArc.c deleted file mode 100644 index ab48720..0000000 --- a/generic/tkCanvArc.c +++ /dev/null @@ -1,1716 +0,0 @@ -/* - * tkCanvArc.c -- - * - * This file implements arc items for canvas widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvArc.c,v 1.3 1998/09/14 18:23:04 stanton Exp $ - */ - -#include <stdio.h> -#include "tkPort.h" -#include "tkInt.h" - -/* - * The structure below defines the record for each arc item. - */ - -typedef struct ArcItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - double bbox[4]; /* Coordinates (x1, y1, x2, y2) of bounding - * box for oval of which arc is a piece. */ - double start; /* Angle at which arc begins, in degrees - * between 0 and 360. */ - double extent; /* Extent of arc (angular distance from - * start to end of arc) in degrees between - * -360 and 360. */ - double *outlinePtr; /* Points to (x,y) coordinates for points - * that define one or two closed polygons - * representing the portion of the outline - * that isn't part of the arc (the V-shape - * for a pie slice or a line-like segment - * for a chord). Malloc'ed. */ - int numOutlinePoints; /* Number of points at outlinePtr. Zero - * means no space allocated. */ - int width; /* Width of outline (in pixels). */ - XColor *outlineColor; /* Color for outline. NULL means don't - * draw outline. */ - XColor *fillColor; /* Color for filling arc (used for drawing - * outline too when style is "arc"). NULL - * means don't fill arc. */ - Pixmap fillStipple; /* Stipple bitmap for filling item. */ - Pixmap outlineStipple; /* Stipple bitmap for outline. */ - Tk_Uid style; /* How to draw arc: arc, chord, or pieslice. */ - GC outlineGC; /* Graphics context for outline. */ - GC fillGC; /* Graphics context for filling item. */ - double center1[2]; /* Coordinates of center of arc outline at - * start (see ComputeArcOutline). */ - double center2[2]; /* Coordinates of center of arc outline at - * start+extent (see ComputeArcOutline). */ -} ArcItem; - -/* - * The definitions below define the sizes of the polygons used to - * display outline information for various styles of arcs: - */ - -#define CHORD_OUTLINE_PTS 7 -#define PIE_OUTLINE1_PTS 6 -#define PIE_OUTLINE2_PTS 7 - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL, - "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ArcItem, outlineStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL, - "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL, - "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ComputeArcBbox _ANSI_ARGS_((Tk_Canvas canvas, - ArcItem *arcPtr)); -static int ConfigureArc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateArc _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteArc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayArc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static int ArcCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -static int ArcToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double ArcToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *coordPtr)); -static int ArcToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static void ScaleArc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateArc _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); -static int AngleInRange _ANSI_ARGS_((double x, double y, - double start, double extent)); -static void ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr)); -static int HorizLineToArc _ANSI_ARGS_((double x1, double x2, - double y, double rx, double ry, - double start, double extent)); -static int VertLineToArc _ANSI_ARGS_((double x, double y1, - double y2, double rx, double ry, - double start, double extent)); - -/* - * The structures below defines the arc item types by means of procedures - * that can be invoked by generic item code. - */ - -Tk_ItemType tkArcType = { - "arc", /* name */ - sizeof(ArcItem), /* itemSize */ - CreateArc, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureArc, /* configureProc */ - ArcCoords, /* coordProc */ - DeleteArc, /* deleteProc */ - DisplayArc, /* displayProc */ - 0, /* alwaysRedraw */ - ArcToPoint, /* pointProc */ - ArcToArea, /* areaProc */ - ArcToPostscript, /* postscriptProc */ - ScaleArc, /* scaleProc */ - TranslateArc, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -#ifndef PI -# define PI 3.14159265358979323846 -#endif - -/* - * The uid's below comprise the legal values for the "-style" - * option for arcs. - */ - -static Tk_Uid arcUid = NULL; -static Tk_Uid chordUid = NULL; -static Tk_Uid pieSliceUid = NULL; - -/* - *-------------------------------------------------------------- - * - * CreateArc -- - * - * This procedure is invoked to create a new arc item in - * a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is - * left uninitialized, so it can be safely freed by the - * caller. - * - * Side effects: - * A new arc item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateArc(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing arc. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Carry out once-only initialization. - */ - - if (arcUid == NULL) { - arcUid = Tk_GetUid("arc"); - chordUid = Tk_GetUid("chord"); - pieSliceUid = Tk_GetUid("pieslice"); - } - - /* - * Carry out initialization that is needed in order to clean - * up after errors during the the remainder of this procedure. - */ - - arcPtr->start = 0; - arcPtr->extent = 90; - arcPtr->outlinePtr = NULL; - arcPtr->numOutlinePoints = 0; - arcPtr->width = 1; - arcPtr->outlineColor = NULL; - arcPtr->fillColor = NULL; - arcPtr->fillStipple = None; - arcPtr->outlineStipple = None; - arcPtr->style = pieSliceUid; - arcPtr->outlineGC = None; - arcPtr->fillGC = None; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &arcPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) != TCL_OK) { - DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ArcCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on arcs. See the user documentation for details - * on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -ArcCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, arcPtr->bbox[0], c0); - Tcl_PrintDouble(interp, arcPtr->bbox[1], c1); - Tcl_PrintDouble(interp, arcPtr->bbox[2], c2); - Tcl_PrintDouble(interp, arcPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &arcPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; - } - ComputeArcBbox(canvas, arcPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 4, got %d", - argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureArc -- - * - * This procedure is invoked to configure various aspects - * of a arc item, such as its outline and fill colors. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information, such as colors and stipple - * patterns, may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Arc item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - XGCValues gcValues; - GC newGC; - unsigned long mask; - int i; - Tk_Window tkwin; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) arcPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as - * style and graphics contexts. - */ - - i = (int) (arcPtr->start/360.0); - arcPtr->start -= i*360.0; - if (arcPtr->start < 0) { - arcPtr->start += 360.0; - } - i = (int) (arcPtr->extent/360.0); - arcPtr->extent -= i*360.0; - - if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid) - && (arcPtr->style != pieSliceUid)) { - Tcl_AppendResult(interp, "bad -style option \"", - arcPtr->style, "\": must be arc, chord, or pieslice", - (char *) NULL); - arcPtr->style = pieSliceUid; - return TCL_ERROR; - } - - if (arcPtr->width < 0) { - arcPtr->width = 1; - } - if (arcPtr->outlineColor == NULL) { - newGC = None; - } else { - gcValues.foreground = arcPtr->outlineColor->pixel; - gcValues.cap_style = CapButt; - gcValues.line_width = arcPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; - if (arcPtr->outlineStipple != None) { - gcValues.stipple = arcPtr->outlineStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), arcPtr->outlineGC); - } - arcPtr->outlineGC = newGC; - - if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) { - newGC = None; - } else { - gcValues.foreground = arcPtr->fillColor->pixel; - if (arcPtr->style == chordUid) { - gcValues.arc_mode = ArcChord; - } else { - gcValues.arc_mode = ArcPieSlice; - } - mask = GCForeground|GCArcMode; - if (arcPtr->fillStipple != None) { - gcValues.stipple = arcPtr->fillStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (arcPtr->fillGC != None) { - Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC); - } - arcPtr->fillGC = newGC; - - ComputeArcBbox(canvas, arcPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteArc -- - * - * This procedure is called to clean up the data structure - * associated with a arc item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteArc(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - - if (arcPtr->numOutlinePoints != 0) { - ckfree((char *) arcPtr->outlinePtr); - } - if (arcPtr->outlineColor != NULL) { - Tk_FreeColor(arcPtr->outlineColor); - } - if (arcPtr->fillColor != NULL) { - Tk_FreeColor(arcPtr->fillColor); - } - if (arcPtr->fillStipple != None) { - Tk_FreeBitmap(display, arcPtr->fillStipple); - } - if (arcPtr->outlineStipple != None) { - Tk_FreeBitmap(display, arcPtr->outlineStipple); - } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(display, arcPtr->outlineGC); - } - if (arcPtr->fillGC != None) { - Tk_FreeGC(display, arcPtr->fillGC); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeArcBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of an arc. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ComputeArcBbox(canvas, arcPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - ArcItem *arcPtr; /* Item whose bbox is to be - * recomputed. */ -{ - double tmp, center[2], point[2]; - - /* - * Make sure that the first coordinates are the lowest ones. - */ - - if (arcPtr->bbox[1] > arcPtr->bbox[3]) { - double tmp; - tmp = arcPtr->bbox[3]; - arcPtr->bbox[3] = arcPtr->bbox[1]; - arcPtr->bbox[1] = tmp; - } - if (arcPtr->bbox[0] > arcPtr->bbox[2]) { - double tmp; - tmp = arcPtr->bbox[2]; - arcPtr->bbox[2] = arcPtr->bbox[0]; - arcPtr->bbox[0] = tmp; - } - - ComputeArcOutline(arcPtr); - - /* - * To compute the bounding box, start with the the bbox formed - * by the two endpoints of the arc. Then add in the center of - * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock, - * 9-o'clock, and 12-o'clock positions, if they are relevant. - */ - - arcPtr->header.x1 = arcPtr->header.x2 = (int) arcPtr->center1[0]; - arcPtr->header.y1 = arcPtr->header.y2 = (int) arcPtr->center1[1]; - TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2); - center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2; - center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2; - if (arcPtr->style == pieSliceUid) { - TkIncludePoint((Tk_Item *) arcPtr, center); - } - - tmp = -arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - point[0] = arcPtr->bbox[2]; - point[1] = center[1]; - TkIncludePoint((Tk_Item *) arcPtr, point); - } - tmp = 90.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - point[0] = center[0]; - point[1] = arcPtr->bbox[1]; - TkIncludePoint((Tk_Item *) arcPtr, point); - } - tmp = 180.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - point[0] = arcPtr->bbox[0]; - point[1] = center[1]; - TkIncludePoint((Tk_Item *) arcPtr, point); - } - tmp = 270.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - point[0] = center[0]; - point[1] = arcPtr->bbox[3]; - TkIncludePoint((Tk_Item *) arcPtr, point); - } - - /* - * Lastly, expand by the width of the arc (if the arc's outline is - * being drawn) and add one extra pixel just for safety. - */ - - if (arcPtr->outlineColor == NULL) { - tmp = 1; - } else { - tmp = (arcPtr->width + 1)/2 + 1; - } - arcPtr->header.x1 -= (int) tmp; - arcPtr->header.y1 -= (int) tmp; - arcPtr->header.x2 += (int) tmp; - arcPtr->header.y2 += (int) tmp; -} - -/* - *-------------------------------------------------------------- - * - * DisplayArc -- - * - * This procedure is invoked to draw an arc item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - short x1, y1, x2, y2; - int start, extent; - - /* - * Compute the screen coordinates of the bounding box for the item, - * plus integer values for the angles. - */ - - Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[0], arcPtr->bbox[1], - &x1, &y1); - Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[2], arcPtr->bbox[3], - &x2, &y2); - if (x2 <= x1) { - x2 = x1+1; - } - if (y2 <= y1) { - y2 = y1+1; - } - start = (int) ((64*arcPtr->start) + 0.5); - extent = (int) ((64*arcPtr->extent) + 0.5); - - /* - * Display filled arc first (if wanted), then outline. If the extent - * is zero then don't invoke XFillArc or XDrawArc, since this causes - * some window servers to crash and should be a no-op anyway. - */ - - if ((arcPtr->fillGC != None) && (extent != 0)) { - if (arcPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->fillGC); - } - XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1), - (unsigned) (y2-y1), start, extent); - if (arcPtr->fillStipple != None) { - XSetTSOrigin(display, arcPtr->fillGC, 0, 0); - } - } - if (arcPtr->outlineGC != None) { - if (arcPtr->outlineStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->outlineGC); - } - if (extent != 0) { - XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, - (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); - } - - /* - * If the outline width is very thin, don't use polygons to draw - * the linear parts of the outline (this often results in nothing - * being displayed); just draw lines instead. - */ - - if (arcPtr->width <= 2) { - Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0], - arcPtr->center1[1], &x1, &y1); - Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0], - arcPtr->center2[1], &x2, &y2); - - if (arcPtr->style == chordUid) { - XDrawLine(display, drawable, arcPtr->outlineGC, - x1, y1, x2, y2); - } else if (arcPtr->style == pieSliceUid) { - short cx, cy; - - Tk_CanvasDrawableCoords(canvas, - (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0, - (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy); - XDrawLine(display, drawable, arcPtr->outlineGC, - cx, cy, x1, y1); - XDrawLine(display, drawable, arcPtr->outlineGC, - cx, cy, x2, y2); - } - } else { - if (arcPtr->style == chordUid) { - TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS, - display, drawable, arcPtr->outlineGC, None); - } else if (arcPtr->style == pieSliceUid) { - TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS, - display, drawable, arcPtr->outlineGC, None); - TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS, display, drawable, arcPtr->outlineGC, - None); - } - } - if (arcPtr->outlineStipple != None) { - XSetTSOrigin(display, arcPtr->outlineGC, 0, 0); - } - } -} - -/* - *-------------------------------------------------------------- - * - * ArcToPoint -- - * - * Computes the distance from a given point to a given - * arc, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the arc. If the - * point isn't inside the arc then the return value is the - * distance from the point to the arc. If itemPtr is filled, - * then anywhere in the interior is considered "inside"; if - * itemPtr isn't filled, then "inside" means only the area - * occupied by the outline. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -ArcToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - double vertex[2], pointAngle, diff, dist, newDist; - double poly[8], polyDist, width, t1, t2; - int filled, angleInRange; - - /* - * See if the point is within the angular range of the arc. - * Remember, X angles are backwards from the way we'd normally - * think of them. Also, compensate for any eccentricity of - * the oval. - */ - - vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; - vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; - t1 = (pointPtr[1] - vertex[1])/(arcPtr->bbox[3] - arcPtr->bbox[1]); - t2 = (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]); - if ((t1 == 0.0) && (t2 == 0.0)) { - pointAngle = 0; - } else { - pointAngle = -atan2(t1, t2)*180/PI; - } - diff = pointAngle - arcPtr->start; - diff -= ((int) (diff/360.0) * 360.0); - if (diff < 0) { - diff += 360.0; - } - angleInRange = (diff <= arcPtr->extent) || - ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent)); - - /* - * Now perform different tests depending on what kind of arc - * we're dealing with. - */ - - if (arcPtr->style == arcUid) { - if (angleInRange) { - return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width, - 0, pointPtr); - } - dist = hypot(pointPtr[0] - arcPtr->center1[0], - pointPtr[1] - arcPtr->center1[1]); - newDist = hypot(pointPtr[0] - arcPtr->center2[0], - pointPtr[1] - arcPtr->center2[1]); - if (newDist < dist) { - return newDist; - } - return dist; - } - - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { - filled = 1; - } else { - filled = 0; - } - if (arcPtr->outlineGC == None) { - width = 0.0; - } else { - width = arcPtr->width; - } - - if (arcPtr->style == pieSliceUid) { - if (width > 1.0) { - dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, - pointPtr); - newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS, pointPtr); - } else { - dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr); - newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr); - } - if (newDist < dist) { - dist = newDist; - } - if (angleInRange) { - newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); - if (newDist < dist) { - dist = newDist; - } - } - return dist; - } - - /* - * This is a chord-style arc. We have to deal specially with the - * triangular piece that represents the difference between a - * chord-style arc and a pie-slice arc (for small angles this piece - * is excluded here where it would be included for pie slices; - * for large angles the piece is included here but would be - * excluded for pie slices). - */ - - if (width > 1.0) { - dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, - pointPtr); - } else { - dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr); - } - poly[0] = poly[6] = vertex[0]; - poly[1] = poly[7] = vertex[1]; - poly[2] = arcPtr->center1[0]; - poly[3] = arcPtr->center1[1]; - poly[4] = arcPtr->center2[0]; - poly[5] = arcPtr->center2[1]; - polyDist = TkPolygonToPoint(poly, 4, pointPtr); - if (angleInRange) { - if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0) - || (polyDist > 0.0)) { - newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); - if (newDist < dist) { - dist = newDist; - } - } - } else { - if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) { - if (filled && (polyDist < dist)) { - dist = polyDist; - } - } - } - return dist; -} - -/* - *-------------------------------------------------------------- - * - * ArcToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given area. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ArcToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against arc. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - double rx, ry; /* Radii for transformed oval: these define - * an oval centered at the origin. */ - double tRect[4]; /* Transformed version of x1, y1, x2, y2, - * for coord. system where arc is centered - * on the origin. */ - double center[2], width, angle, tmp; - double points[20], *pointPtr; - int numPoints, filled; - int inside; /* Non-zero means every test so far suggests - * that arc is inside rectangle. 0 means - * every test so far shows arc to be outside - * of rectangle. */ - int newInside; - - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { - filled = 1; - } else { - filled = 0; - } - if (arcPtr->outlineGC == None) { - width = 0.0; - } else { - width = arcPtr->width; - } - - /* - * Transform both the arc and the rectangle so that the arc's oval - * is centered on the origin. - */ - - center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; - center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; - tRect[0] = rectPtr[0] - center[0]; - tRect[1] = rectPtr[1] - center[1]; - tRect[2] = rectPtr[2] - center[0]; - tRect[3] = rectPtr[3] - center[1]; - rx = arcPtr->bbox[2] - center[0] + width/2.0; - ry = arcPtr->bbox[3] - center[1] + width/2.0; - - /* - * Find the extreme points of the arc and see whether these are all - * inside the rectangle (in which case we're done), partly in and - * partly out (in which case we're done), or all outside (in which - * case we have more work to do). The extreme points include the - * following, which are checked in order: - * - * 1. The outside points of the arc, corresponding to start and - * extent. - * 2. The center of the arc (but only in pie-slice mode). - * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc - * includes those angles). - */ - - pointPtr = points; - angle = -arcPtr->start*(PI/180.0); - pointPtr[0] = rx*cos(angle); - pointPtr[1] = ry*sin(angle); - angle += -arcPtr->extent*(PI/180.0); - pointPtr[2] = rx*cos(angle); - pointPtr[3] = ry*sin(angle); - numPoints = 2; - pointPtr += 4; - - if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) { - pointPtr[0] = 0.0; - pointPtr[1] = 0.0; - numPoints++; - pointPtr += 2; - } - - tmp = -arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - pointPtr[0] = rx; - pointPtr[1] = 0.0; - numPoints++; - pointPtr += 2; - } - tmp = 90.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - pointPtr[0] = 0.0; - pointPtr[1] = -ry; - numPoints++; - pointPtr += 2; - } - tmp = 180.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - pointPtr[0] = -rx; - pointPtr[1] = 0.0; - numPoints++; - pointPtr += 2; - } - tmp = 270.0 - arcPtr->start; - if (tmp < 0) { - tmp += 360.0; - } - if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { - pointPtr[0] = 0.0; - pointPtr[1] = ry; - numPoints++; - } - - /* - * Now that we've located the extreme points, loop through them all - * to see which are inside the rectangle. - */ - - inside = (points[0] > tRect[0]) && (points[0] < tRect[2]) - && (points[1] > tRect[1]) && (points[1] < tRect[3]); - for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) { - newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2]) - && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]); - if (newInside != inside) { - return 0; - } - } - - if (inside) { - return 1; - } - - /* - * So far, oval appears to be outside rectangle, but can't yet tell - * for sure. Next, test each of the four sides of the rectangle - * against the bounding region for the arc. If any intersections - * are found, then return "overlapping". First, test against the - * polygon(s) forming the sides of a chord or pie-slice. - */ - - if (arcPtr->style == pieSliceUid) { - if (width >= 1.0) { - if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, - rectPtr) != -1) { - return 0; - } - if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS, rectPtr) != -1) { - return 0; - } - } else { - if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) || - (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) { - return 0; - } - } - } else if (arcPtr->style == chordUid) { - if (width >= 1.0) { - if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, - rectPtr) != -1) { - return 0; - } - } else { - if (TkLineToArea(arcPtr->center1, arcPtr->center2, - rectPtr) != -1) { - return 0; - } - } - } - - /* - * Next check for overlap between each of the four sides and the - * outer perimiter of the arc. If the arc isn't filled, then also - * check the inner perimeter of the arc. - */ - - if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, - arcPtr->extent) - || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent) - || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent) - || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent)) { - return 0; - } - if ((width > 1.0) && !filled) { - rx -= width; - ry -= width; - if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, - arcPtr->extent) - || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent) - || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent) - || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, - arcPtr->start, arcPtr->extent)) { - return 0; - } - } - - /* - * The arc still appears to be totally disjoint from the rectangle, - * but it's also possible that the rectangle is totally inside the arc. - * Do one last check, which is to check one point of the rectangle - * to see if it's inside the arc. If it is, we've got overlap. If - * it isn't, the arc's really outside the rectangle. - */ - - if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) { - return 0; - } - return -1; -} - -/* - *-------------------------------------------------------------- - * - * ScaleArc -- - * - * This procedure is invoked to rescale an arc item. - * - * Results: - * None. - * - * Side effects: - * The arc referred to by itemPtr is rescaled so that the - * following transformation is applied to all point - * coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleArc(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing arc. */ - Tk_Item *itemPtr; /* Arc to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - - arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX); - arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY); - arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX); - arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY); - ComputeArcBbox(canvas, arcPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateArc -- - * - * This procedure is called to move an arc by a given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the arc is offset by (xDelta, yDelta), and - * the bounding box is updated in the generic part of the item - * structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateArc(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - - arcPtr->bbox[0] += deltaX; - arcPtr->bbox[1] += deltaY; - arcPtr->bbox[2] += deltaX; - arcPtr->bbox[3] += deltaY; - ComputeArcBbox(canvas, arcPtr); -} - -/* - *-------------------------------------------------------------- - * - * ComputeArcOutline -- - * - * This procedure creates a polygon describing everything in - * the outline for an arc except what's in the curved part. - * For a "pie slice" arc this is a V-shaped chunk, and for - * a "chord" arc this is a linear chunk (with cutaway corners). - * For "arc" arcs, this stuff isn't relevant. - * - * Results: - * None. - * - * Side effects: - * The information at arcPtr->outlinePtr gets modified, and - * storage for arcPtr->outlinePtr may be allocated or freed. - * - *-------------------------------------------------------------- - */ - -static void -ComputeArcOutline(arcPtr) - ArcItem *arcPtr; /* Information about arc. */ -{ - double sin1, cos1, sin2, cos2, angle, halfWidth; - double boxWidth, boxHeight; - double vertex[2], corner1[2], corner2[2]; - double *outlinePtr; - - /* - * Make sure that the outlinePtr array is large enough to hold - * either a chord or pie-slice outline. - */ - - if (arcPtr->numOutlinePoints == 0) { - arcPtr->outlinePtr = (double *) ckalloc((unsigned) - (26 * sizeof(double))); - arcPtr->numOutlinePoints = 22; - } - outlinePtr = arcPtr->outlinePtr; - - /* - * First compute the two points that lie at the centers of - * the ends of the curved arc segment, which are marked with - * X's in the figure below: - * - * - * * * * - * * * - * * * * * - * * * * * - * * * * * - * X * * X - * - * The code is tricky because the arc can be ovular in shape. - * It computes the position for a unit circle, and then - * scales to fit the shape of the arc's bounding box. - * - * Also, watch out because angles go counter-clockwise like you - * might expect, but the y-coordinate system is inverted. To - * handle this, just negate the angles in all the computations. - */ - - boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0]; - boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1]; - angle = -arcPtr->start*PI/180.0; - sin1 = sin(angle); - cos1 = cos(angle); - angle -= arcPtr->extent*PI/180.0; - sin2 = sin(angle); - cos2 = cos(angle); - vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; - vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; - arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0; - arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0; - arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0; - arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0; - - /* - * Next compute the "outermost corners" of the arc, which are - * marked with X's in the figure below: - * - * * * * - * * * - * * * * * - * * * * * - * X * * X - * * * - * - * The code below is tricky because it has to handle eccentricity - * in the shape of the oval. The key in the code below is to - * realize that the slope of the line from arcPtr->center1 to corner1 - * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2 - * and corner2. These formulas can be computed from the formula for - * the oval. - */ - - halfWidth = arcPtr->width/2.0; - if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { - angle = 0.0; - } else { - angle = atan2(boxWidth*sin1, boxHeight*cos1); - } - corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth; - corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth; - if (((boxWidth*sin2) == 0.0) && ((boxHeight*cos2) == 0.0)) { - angle = 0.0; - } else { - angle = atan2(boxWidth*sin2, boxHeight*cos2); - } - corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth; - corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth; - - /* - * For a chord outline, generate a six-sided polygon with three - * points for each end of the chord. The first and third points - * for each end are butt points generated on either side of the - * center point. The second point is the corner point. - */ - - if (arcPtr->style == chordUid) { - outlinePtr[0] = outlinePtr[12] = corner1[0]; - outlinePtr[1] = outlinePtr[13] = corner1[1]; - TkGetButtPoints(arcPtr->center2, arcPtr->center1, - (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2); - outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2] - - arcPtr->center1[0]; - outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3] - - arcPtr->center1[1]; - outlinePtr[6] = corner2[0]; - outlinePtr[7] = corner2[1]; - outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10] - - arcPtr->center1[0]; - outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11] - - arcPtr->center1[1]; - } else if (arcPtr->style == pieSliceUid) { - /* - * For pie slices, generate two polygons, one for each side - * of the pie slice. The first arm has a shape like this, - * where the center of the oval is X, arcPtr->center1 is at Y, and - * corner1 is at Z: - * - * _____________________ - * | \ - * | \ - * X Y Z - * | / - * |_____________________/ - * - */ - - TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0, - outlinePtr, outlinePtr+2); - outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0]; - outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1]; - outlinePtr[6] = corner1[0]; - outlinePtr[7] = corner1[1]; - outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0]; - outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1]; - outlinePtr[10] = outlinePtr[0]; - outlinePtr[11] = outlinePtr[1]; - - /* - * The second arm has a shape like this: - * - * - * ______________________ - * / \ - * / \ - * Z Y X / - * \ / - * \______________________/ - * - * Similar to above X is the center of the oval/circle, Y is - * arcPtr->center2, and Z is corner2. The extra jog out to the left - * of X is needed in or to produce a butted joint with the - * first arm; the corner to the right of X is one of the - * first two points of the first arm, depending on extent. - */ - - TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0, - outlinePtr+12, outlinePtr+16); - if ((arcPtr->extent > 180) || - ((arcPtr->extent < 0) && (arcPtr->extent > -180))) { - outlinePtr[14] = outlinePtr[0]; - outlinePtr[15] = outlinePtr[1]; - } else { - outlinePtr[14] = outlinePtr[2]; - outlinePtr[15] = outlinePtr[3]; - } - outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0]; - outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1]; - outlinePtr[20] = corner2[0]; - outlinePtr[21] = corner2[1]; - outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0]; - outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1]; - outlinePtr[24] = outlinePtr[12]; - outlinePtr[25] = outlinePtr[13]; - } -} - -/* - *-------------------------------------------------------------- - * - * HorizLineToArc -- - * - * Determines whether a horizontal line segment intersects - * a given arc. - * - * Results: - * The return value is 1 if the given line intersects the - * infinitely-thin arc section defined by rx, ry, start, - * and extent, and 0 otherwise. Only the perimeter of the - * arc is checked: interior areas (e.g. pie-slice or chord) - * are not checked. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -HorizLineToArc(x1, x2, y, rx, ry, start, extent) - double x1, x2; /* X-coords of endpoints of line segment. - * X1 must be <= x2. */ - double y; /* Y-coordinate of line segment. */ - double rx, ry; /* These x- and y-radii define an oval - * centered at the origin. */ - double start, extent; /* Angles that define extent of arc, in - * the standard fashion for this module. */ -{ - double tmp; - double tx, ty; /* Coordinates of intersection point in - * transformed coordinate system. */ - double x; - - /* - * Compute the x-coordinate of one possible intersection point - * between the arc and the line. Use a transformed coordinate - * system where the oval is a unit circle centered at the origin. - * Then scale back to get actual x-coordinate. - */ - - ty = y/ry; - tmp = 1 - ty*ty; - if (tmp < 0) { - return 0; - } - tx = sqrt(tmp); - x = tx*rx; - - /* - * Test both intersection points. - */ - - if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) { - return 1; - } - if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * VertLineToArc -- - * - * Determines whether a vertical line segment intersects - * a given arc. - * - * Results: - * The return value is 1 if the given line intersects the - * infinitely-thin arc section defined by rx, ry, start, - * and extent, and 0 otherwise. Only the perimeter of the - * arc is checked: interior areas (e.g. pie-slice or chord) - * are not checked. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -VertLineToArc(x, y1, y2, rx, ry, start, extent) - double x; /* X-coordinate of line segment. */ - double y1, y2; /* Y-coords of endpoints of line segment. - * Y1 must be <= y2. */ - double rx, ry; /* These x- and y-radii define an oval - * centered at the origin. */ - double start, extent; /* Angles that define extent of arc, in - * the standard fashion for this module. */ -{ - double tmp; - double tx, ty; /* Coordinates of intersection point in - * transformed coordinate system. */ - double y; - - /* - * Compute the y-coordinate of one possible intersection point - * between the arc and the line. Use a transformed coordinate - * system where the oval is a unit circle centered at the origin. - * Then scale back to get actual y-coordinate. - */ - - tx = x/rx; - tmp = 1 - tx*tx; - if (tmp < 0) { - return 0; - } - ty = sqrt(tmp); - y = ty*ry; - - /* - * Test both intersection points. - */ - - if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) { - return 1; - } - if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * AngleInRange -- - * - * Determine whether the angle from the origin to a given - * point is within a given range. - * - * Results: - * The return value is 1 if the angle from (0,0) to (x,y) - * is in the range given by start and extent, where angles - * are interpreted in the standard way for ovals (meaning - * backwards from normal interpretation). Otherwise the - * return value is 0. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -AngleInRange(x, y, start, extent) - double x, y; /* Coordinate of point; angle measured - * from origin to here, relative to x-axis. */ - double start; /* First angle, degrees, >=0, <=360. */ - double extent; /* Size of arc in degrees >=-360, <=360. */ -{ - double diff; - - if ((x == 0.0) && (y == 0.0)) { - return 1; - } - diff = -atan2(y, x); - diff = diff*(180.0/PI) - start; - while (diff > 360.0) { - diff -= 360.0; - } - while (diff < 0.0) { - diff += 360.0; - } - if (extent >= 0) { - return diff <= extent; - } - return (diff-360.0) >= extent; -} - -/* - *-------------------------------------------------------------- - * - * ArcToPostscript -- - * - * This procedure is called to generate Postscript for - * arc items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used - * to be there. If no error occurs, then Postscript for the - * item is appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -ArcToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - ArcItem *arcPtr = (ArcItem *) itemPtr; - char buffer[400]; - double y1, y2, ang1, ang2; - - y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]); - y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]); - ang1 = arcPtr->start; - ang2 = ang1 + arcPtr->extent; - if (ang2 < ang1) { - ang1 = ang2; - ang2 = arcPtr->start; - } - - /* - * If the arc is filled, output Postscript for the interior region - * of the arc. - */ - - if (arcPtr->fillGC != None) { - sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", - (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, - (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (arcPtr->style == chordUid) { - sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", - ang1, ang2); - } else { - sprintf(buffer, - "0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", - ang1, ang2); - } - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->fillColor) != TCL_OK) { - return TCL_ERROR; - }; - if (arcPtr->fillStipple != None) { - Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, arcPtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - if (arcPtr->outlineGC != None) { - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - } - } else { - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - } - - /* - * If there's an outline for the arc, draw it. - */ - - if (arcPtr->outlineGC != None) { - sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", - (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, - (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "0 0 1 %.15g %.15g arc\nsetmatrix\n", ang1, ang2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "%d setlinewidth\n0 setlinecap\n", arcPtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) - != TCL_OK) { - return TCL_ERROR; - } - if (arcPtr->outlineStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - if (arcPtr->style != arcUid) { - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - if (arcPtr->style == chordUid) { - Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, - CHORD_OUTLINE_PTS); - } else { - Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, - PIE_OUTLINE1_PTS); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) - != TCL_OK) { - return TCL_ERROR; - } - if (arcPtr->outlineStipple != None) { - Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - Tk_CanvasPsPath(interp, canvas, - arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS); - } - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) - != TCL_OK) { - return TCL_ERROR; - } - if (arcPtr->outlineStipple != None) { - Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - } - } - - return TCL_OK; -} diff --git a/generic/tkCanvBmap.c b/generic/tkCanvBmap.c deleted file mode 100644 index a09bf8d..0000000 --- a/generic/tkCanvBmap.c +++ /dev/null @@ -1,800 +0,0 @@ -/* - * tkCanvBmap.c -- - * - * This file implements bitmap items for canvas widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvBmap.c,v 1.2 1998/09/14 18:23:04 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" -#include "tkCanvas.h" - -/* - * The structure below defines the record for each bitmap item. - */ - -typedef struct BitmapItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - double x, y; /* Coordinates of positioning point for - * bitmap. */ - Tk_Anchor anchor; /* Where to anchor bitmap relative to - * (x,y). */ - Pixmap bitmap; /* Bitmap to display in window. */ - XColor *fgColor; /* Foreground color to use for bitmap. */ - XColor *bgColor; /* Background color to use for bitmap. */ - GC gc; /* Graphics context to use for drawing - * bitmap on screen. */ -} BitmapItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, - "center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_COLOR, "-background", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, - "black", Tk_Offset(BitmapItem, fgColor), 0}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static int BitmapCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -static int BitmapToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double BitmapToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *coordPtr)); -static int BitmapToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static void ComputeBitmapBbox _ANSI_ARGS_((Tk_Canvas canvas, - BitmapItem *bmapPtr)); -static int ConfigureBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteBitmap _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayBitmap _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static void ScaleBitmap _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateBitmap _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * The structures below defines the bitmap item type in terms of - * procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkBitmapType = { - "bitmap", /* name */ - sizeof(BitmapItem), /* itemSize */ - CreateBitmap, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureBitmap, /* configureProc */ - BitmapCoords, /* coordProc */ - DeleteBitmap, /* deleteProc */ - DisplayBitmap, /* displayProc */ - 0, /* alwaysRedraw */ - BitmapToPoint, /* pointProc */ - BitmapToArea, /* areaProc */ - BitmapToPostscript, /* postscriptProc */ - ScaleBitmap, /* scaleProc */ - TranslateBitmap, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - *-------------------------------------------------------------- - * - * CreateBitmap -- - * - * This procedure is invoked to create a new bitmap - * item in a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, - * so it can be safely freed by the caller. - * - * Side effects: - * A new bitmap item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateBitmap(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x y ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Initialize item's record. - */ - - bmapPtr->anchor = TK_ANCHOR_CENTER; - bmapPtr->bitmap = None; - bmapPtr->fgColor = NULL; - bmapPtr->bgColor = NULL; - bmapPtr->gc = None; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureBitmap(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * BitmapCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on bitmap items. See the user documentation for - * details on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -BitmapCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, bmapPtr->x, x); - Tcl_PrintDouble(interp, bmapPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { - return TCL_ERROR; - } - ComputeBitmapBbox(canvas, bmapPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureBitmap -- - * - * This procedure is invoked to configure various aspects - * of a bitmap item, such as its anchor position. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Bitmap item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - XGCValues gcValues; - GC newGC; - Tk_Window tkwin; - unsigned long mask; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) bmapPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as those - * that determine the graphics context. - */ - - gcValues.foreground = bmapPtr->fgColor->pixel; - mask = GCForeground; - if (bmapPtr->bgColor != NULL) { - gcValues.background = bmapPtr->bgColor->pixel; - mask |= GCBackground; - } else { - gcValues.clip_mask = bmapPtr->bitmap; - mask |= GCClipMask; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - if (bmapPtr->gc != None) { - Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc); - } - bmapPtr->gc = newGC; - - ComputeBitmapBbox(canvas, bmapPtr); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteBitmap -- - * - * This procedure is called to clean up the data structure - * associated with a bitmap item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteBitmap(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - - if (bmapPtr->bitmap != None) { - Tk_FreeBitmap(display, bmapPtr->bitmap); - } - if (bmapPtr->fgColor != NULL) { - Tk_FreeColor(bmapPtr->fgColor); - } - if (bmapPtr->bgColor != NULL) { - Tk_FreeColor(bmapPtr->bgColor); - } - if (bmapPtr->gc != NULL) { - Tk_FreeGC(display, bmapPtr->gc); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeBitmapBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a bitmap item. - * This procedure is where the child bitmap's placement is - * computed. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ComputeBitmapBbox(canvas, bmapPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - BitmapItem *bmapPtr; /* Item whose bbox is to be - * recomputed. */ -{ - int width, height; - int x, y; - - x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5)); - y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5)); - - if (bmapPtr->bitmap == None) { - bmapPtr->header.x1 = bmapPtr->header.x2 = x; - bmapPtr->header.y1 = bmapPtr->header.y2 = y; - return; - } - - /* - * Compute location and size of bitmap, using anchor information. - */ - - Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bmapPtr->bitmap, - &width, &height); - switch (bmapPtr->anchor) { - case TK_ANCHOR_N: - x -= width/2; - break; - case TK_ANCHOR_NE: - x -= width; - break; - case TK_ANCHOR_E: - x -= width; - y -= height/2; - break; - case TK_ANCHOR_SE: - x -= width; - y -= height; - break; - case TK_ANCHOR_S: - x -= width/2; - y -= height; - break; - case TK_ANCHOR_SW: - y -= height; - break; - case TK_ANCHOR_W: - y -= height/2; - break; - case TK_ANCHOR_NW: - break; - case TK_ANCHOR_CENTER: - x -= width/2; - y -= height/2; - break; - } - - /* - * Store the information in the item header. - */ - - bmapPtr->header.x1 = x; - bmapPtr->header.y1 = y; - bmapPtr->header.x2 = x + width; - bmapPtr->header.y2 = y + height; -} - -/* - *-------------------------------------------------------------- - * - * DisplayBitmap -- - * - * This procedure is invoked to draw a bitmap item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - int bmapX, bmapY, bmapWidth, bmapHeight; - short drawableX, drawableY; - - /* - * If the area being displayed doesn't cover the whole bitmap, - * then only redisplay the part of the bitmap that needs - * redisplay. - */ - - if (bmapPtr->bitmap != None) { - if (x > bmapPtr->header.x1) { - bmapX = x - bmapPtr->header.x1; - bmapWidth = bmapPtr->header.x2 - x; - } else { - bmapX = 0; - if ((x+width) < bmapPtr->header.x2) { - bmapWidth = x + width - bmapPtr->header.x1; - } else { - bmapWidth = bmapPtr->header.x2 - bmapPtr->header.x1; - } - } - if (y > bmapPtr->header.y1) { - bmapY = y - bmapPtr->header.y1; - bmapHeight = bmapPtr->header.y2 - y; - } else { - bmapY = 0; - if ((y+height) < bmapPtr->header.y2) { - bmapHeight = y + height - bmapPtr->header.y1; - } else { - bmapHeight = bmapPtr->header.y2 - bmapPtr->header.y1; - } - } - Tk_CanvasDrawableCoords(canvas, - (double) (bmapPtr->header.x1 + bmapX), - (double) (bmapPtr->header.y1 + bmapY), - &drawableX, &drawableY); - - /* - * Must modify the mask origin within the graphics context - * to line up with the bitmap's origin (in order to make - * bitmaps with "-background {}" work right). - */ - - XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX, - drawableY - bmapY); - XCopyPlane(display, bmapPtr->bitmap, drawable, - bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth, - (unsigned int) bmapHeight, drawableX, drawableY, 1); - } -} - -/* - *-------------------------------------------------------------- - * - * BitmapToPoint -- - * - * Computes the distance from a given point to a given - * rectangle, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the bitmap. If the - * point isn't inside the bitmap then the return value is the - * distance from the point to the bitmap. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -BitmapToPoint(canvas, itemPtr, coordPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *coordPtr; /* Pointer to x and y coordinates. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - double x1, x2, y1, y2, xDiff, yDiff; - - x1 = bmapPtr->header.x1; - y1 = bmapPtr->header.y1; - x2 = bmapPtr->header.x2; - y2 = bmapPtr->header.y2; - - /* - * Point is outside rectangle. - */ - - if (coordPtr[0] < x1) { - xDiff = x1 - coordPtr[0]; - } else if (coordPtr[0] > x2) { - xDiff = coordPtr[0] - x2; - } else { - xDiff = 0; - } - - if (coordPtr[1] < y1) { - yDiff = y1 - coordPtr[1]; - } else if (coordPtr[1] > y2) { - yDiff = coordPtr[1] - y2; - } else { - yDiff = 0; - } - - return hypot(xDiff, yDiff); -} - -/* - *-------------------------------------------------------------- - * - * BitmapToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangle. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -BitmapToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against rectangle. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - - if ((rectPtr[2] <= bmapPtr->header.x1) - || (rectPtr[0] >= bmapPtr->header.x2) - || (rectPtr[3] <= bmapPtr->header.y1) - || (rectPtr[1] >= bmapPtr->header.y2)) { - return -1; - } - if ((rectPtr[0] <= bmapPtr->header.x1) - && (rectPtr[1] <= bmapPtr->header.y1) - && (rectPtr[2] >= bmapPtr->header.x2) - && (rectPtr[3] >= bmapPtr->header.y2)) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * ScaleBitmap -- - * - * This procedure is invoked to rescale a bitmap item in a - * canvas. It is one of the standard item procedures for - * bitmap items, and is invoked by the generic canvas code. - * - * Results: - * None. - * - * Side effects: - * The item referred to by itemPtr is rescaled so that the - * following transformation is applied to all point coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleBitmap(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale item. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - - bmapPtr->x = originX + scaleX*(bmapPtr->x - originX); - bmapPtr->y = originY + scaleY*(bmapPtr->y - originY); - ComputeBitmapBbox(canvas, bmapPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateBitmap -- - * - * This procedure is called to move an item by a given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the item is offset by (xDelta, yDelta), and - * the bounding box is updated in the generic part of the item - * structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateBitmap(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - - bmapPtr->x += deltaX; - bmapPtr->y += deltaY; - ComputeBitmapBbox(canvas, bmapPtr); -} - -/* - *-------------------------------------------------------------- - * - * BitmapToPostscript -- - * - * This procedure is called to generate Postscript for - * bitmap items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used to be there. - * If no error occurs, then Postscript for the item is appended - * to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -BitmapToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - double x, y; - int width, height, rowsAtOnce, rowsThisTime; - int curRow; - char buffer[200]; - - if (bmapPtr->bitmap == None) { - return TCL_OK; - } - - /* - * Compute the coordinates of the lower-left corner of the bitmap, - * taking into account the anchor position for the bitmp. - */ - - x = bmapPtr->x; - y = Tk_CanvasPsY(canvas, bmapPtr->y); - Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)), bmapPtr->bitmap, - &width, &height); - switch (bmapPtr->anchor) { - case TK_ANCHOR_NW: y -= height; break; - case TK_ANCHOR_N: x -= width/2.0; y -= height; break; - case TK_ANCHOR_NE: x -= width; y -= height; break; - case TK_ANCHOR_E: x -= width; y -= height/2.0; break; - case TK_ANCHOR_SE: x -= width; break; - case TK_ANCHOR_S: x -= width/2.0; break; - case TK_ANCHOR_SW: break; - case TK_ANCHOR_W: y -= height/2.0; break; - case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; - } - - /* - * Color the background, if there is one. - */ - - if (bmapPtr->bgColor != NULL) { - sprintf(buffer, - "%.15g %.15g moveto %d 0 rlineto 0 %d rlineto %d %s\n", - x, y, width, height, -width,"0 rlineto closepath"); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, bmapPtr->bgColor) != TCL_OK) { - return TCL_ERROR; - } - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - - /* - * Draw the bitmap, if there is a foreground color. If the bitmap - * is very large, then chop it up into multiple bitmaps, each - * consisting of one or more rows. This is needed because Postscript - * can't handle single strings longer than 64 KBytes long. - */ - - if (bmapPtr->fgColor != NULL) { - if (Tk_CanvasPsColor(interp, canvas, bmapPtr->fgColor) != TCL_OK) { - return TCL_ERROR; - } - if (width > 60000) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't generate Postscript", - " for bitmaps more than 60000 pixels wide", - (char *) NULL); - return TCL_ERROR; - } - rowsAtOnce = 60000/width; - if (rowsAtOnce < 1) { - rowsAtOnce = 1; - } - sprintf(buffer, "%.15g %.15g translate\n", x, y+height); - Tcl_AppendResult(interp, buffer, (char *) NULL); - for (curRow = 0; curRow < height; curRow += rowsAtOnce) { - rowsThisTime = rowsAtOnce; - if (rowsThisTime > (height - curRow)) { - rowsThisTime = height - curRow; - } - sprintf(buffer, "0 -%.15g translate\n%d %d true matrix {\n", - (double) rowsThisTime, width, rowsThisTime); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsBitmap(interp, canvas, bmapPtr->bitmap, - 0, curRow, width, rowsThisTime) != TCL_OK) { - return TCL_ERROR; - } - Tcl_AppendResult(interp, "\n} imagemask\n", (char *) NULL); - } - } - return TCL_OK; -} diff --git a/generic/tkCanvImg.c b/generic/tkCanvImg.c deleted file mode 100644 index 0432bd7..0000000 --- a/generic/tkCanvImg.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * tkCanvImg.c -- - * - * This file implements image items for canvas widgets. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvImg.c,v 1.2 1998/09/14 18:23:05 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" -#include "tkCanvas.h" - -/* - * The structure below defines the record for each image item. - */ - -typedef struct ImageItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - Tk_Canvas canvas; /* Canvas containing the image. */ - double x, y; /* Coordinates of positioning point for - * image. */ - Tk_Anchor anchor; /* Where to anchor image relative to - * (x,y). */ - char *imageString; /* String describing -image option (malloc-ed). - * NULL means no image right now. */ - Tk_Image image; /* Image to display in window, or NULL if - * no image at present. */ -} ImageItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, - "center", Tk_Offset(ImageItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ImageItem, imageString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, - int x, int y, int width, int height, int imgWidth, - int imgHeight)); -static int ImageCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -static int ImageToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double ImageToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *coordPtr)); -static void ComputeImageBbox _ANSI_ARGS_((Tk_Canvas canvas, - ImageItem *imgPtr)); -static int ConfigureImage _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateImage _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteImage _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayImage _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static void ScaleImage _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateImage _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * The structures below defines the image item type in terms of - * procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkImageType = { - "image", /* name */ - sizeof(ImageItem), /* itemSize */ - CreateImage, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureImage, /* configureProc */ - ImageCoords, /* coordProc */ - DeleteImage, /* deleteProc */ - DisplayImage, /* displayProc */ - 0, /* alwaysRedraw */ - ImageToPoint, /* pointProc */ - ImageToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ - ScaleImage, /* scaleProc */ - TranslateImage, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - *-------------------------------------------------------------- - * - * CreateImage -- - * - * This procedure is invoked to create a new image - * item in a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, - * so it can be safely freed by the caller. - * - * Side effects: - * A new image item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateImage(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x y ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Initialize item's record. - */ - - imgPtr->canvas = canvas; - imgPtr->anchor = TK_ANCHOR_CENTER; - imgPtr->imageString = NULL; - imgPtr->image = NULL; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &imgPtr->y) - != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureImage(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ImageCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on image items. See the user documentation for - * details on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -ImageCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, imgPtr->x, x); - Tcl_PrintDouble(interp, imgPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &imgPtr->y) != TCL_OK)) { - return TCL_ERROR; - } - ComputeImageBbox(canvas, imgPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureImage -- - * - * This procedure is invoked to configure various aspects - * of an image item, such as its anchor position. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Image item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - Tk_Window tkwin; - Tk_Image image; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, - argv, (char *) imgPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Create the image. Save the old image around and don't free it - * until after the new one is allocated. This keeps the reference - * count from going to zero so the image doesn't have to be recreated - * if it hasn't changed. - */ - - if (imgPtr->imageString != NULL) { - image = Tk_GetImage(interp, tkwin, imgPtr->imageString, - ImageChangedProc, (ClientData) imgPtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (imgPtr->image != NULL) { - Tk_FreeImage(imgPtr->image); - } - imgPtr->image = image; - ComputeImageBbox(canvas, imgPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteImage -- - * - * This procedure is called to clean up the data structure - * associated with a image item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteImage(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - - if (imgPtr->imageString != NULL) { - ckfree(imgPtr->imageString); - } - if (imgPtr->image != NULL) { - Tk_FreeImage(imgPtr->image); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeImageBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a image item. - * This procedure is where the child image's placement is - * computed. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ComputeImageBbox(canvas, imgPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - ImageItem *imgPtr; /* Item whose bbox is to be - * recomputed. */ -{ - int width, height; - int x, y; - - x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5)); - y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5)); - - if (imgPtr->image == None) { - imgPtr->header.x1 = imgPtr->header.x2 = x; - imgPtr->header.y1 = imgPtr->header.y2 = y; - return; - } - - /* - * Compute location and size of image, using anchor information. - */ - - Tk_SizeOfImage(imgPtr->image, &width, &height); - switch (imgPtr->anchor) { - case TK_ANCHOR_N: - x -= width/2; - break; - case TK_ANCHOR_NE: - x -= width; - break; - case TK_ANCHOR_E: - x -= width; - y -= height/2; - break; - case TK_ANCHOR_SE: - x -= width; - y -= height; - break; - case TK_ANCHOR_S: - x -= width/2; - y -= height; - break; - case TK_ANCHOR_SW: - y -= height; - break; - case TK_ANCHOR_W: - y -= height/2; - break; - case TK_ANCHOR_NW: - break; - case TK_ANCHOR_CENTER: - x -= width/2; - y -= height/2; - break; - } - - /* - * Store the information in the item header. - */ - - imgPtr->header.x1 = x; - imgPtr->header.y1 = y; - imgPtr->header.x2 = x + width; - imgPtr->header.y2 = y + height; -} - -/* - *-------------------------------------------------------------- - * - * DisplayImage -- - * - * This procedure is invoked to draw a image item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayImage(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - short drawableX, drawableY; - - if (imgPtr->image == NULL) { - return; - } - - /* - * Translate the coordinates to those of the image, then redisplay it. - */ - - Tk_CanvasDrawableCoords(canvas, (double) x, (double) y, - &drawableX, &drawableY); - Tk_RedrawImage(imgPtr->image, x - imgPtr->header.x1, y - imgPtr->header.y1, - width, height, drawable, drawableX, drawableY); -} - -/* - *-------------------------------------------------------------- - * - * ImageToPoint -- - * - * Computes the distance from a given point to a given - * rectangle, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the image. If the - * point isn't inside the image then the return value is the - * distance from the point to the image. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static double -ImageToPoint(canvas, itemPtr, coordPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *coordPtr; /* Pointer to x and y coordinates. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - double x1, x2, y1, y2, xDiff, yDiff; - - x1 = imgPtr->header.x1; - y1 = imgPtr->header.y1; - x2 = imgPtr->header.x2; - y2 = imgPtr->header.y2; - - /* - * Point is outside rectangle. - */ - - if (coordPtr[0] < x1) { - xDiff = x1 - coordPtr[0]; - } else if (coordPtr[0] > x2) { - xDiff = coordPtr[0] - x2; - } else { - xDiff = 0; - } - - if (coordPtr[1] < y1) { - yDiff = y1 - coordPtr[1]; - } else if (coordPtr[1] > y2) { - yDiff = coordPtr[1] - y2; - } else { - yDiff = 0; - } - - return hypot(xDiff, yDiff); -} - -/* - *-------------------------------------------------------------- - * - * ImageToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangle. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -ImageToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against rectangle. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - - if ((rectPtr[2] <= imgPtr->header.x1) - || (rectPtr[0] >= imgPtr->header.x2) - || (rectPtr[3] <= imgPtr->header.y1) - || (rectPtr[1] >= imgPtr->header.y2)) { - return -1; - } - if ((rectPtr[0] <= imgPtr->header.x1) - && (rectPtr[1] <= imgPtr->header.y1) - && (rectPtr[2] >= imgPtr->header.x2) - && (rectPtr[3] >= imgPtr->header.y2)) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * ScaleImage -- - * - * This procedure is invoked to rescale an item. - * - * Results: - * None. - * - * Side effects: - * The item referred to by itemPtr is rescaled so that the - * following transformation is applied to all point coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleImage(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - - imgPtr->x = originX + scaleX*(imgPtr->x - originX); - imgPtr->y = originY + scaleY*(imgPtr->y - originY); - ComputeImageBbox(canvas, imgPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateImage -- - * - * This procedure is called to move an item by a given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the item is offset by (xDelta, yDelta), and - * the bounding box is updated in the generic part of the item - * structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateImage(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - ImageItem *imgPtr = (ImageItem *) itemPtr; - - imgPtr->x += deltaX; - imgPtr->y += deltaY; - ComputeImageBbox(canvas, imgPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImageChangedProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the image's size or - * how it is displayed. - * - * Results: - * None. - * - * Side effects: - * Arranges for the canvas to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -ImageChangedProc(clientData, x, y, width, height, imgWidth, imgHeight) - ClientData clientData; /* Pointer to canvas item for image. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - ImageItem *imgPtr = (ImageItem *) clientData; - - /* - * If the image's size changed and it's not anchored at its - * northwest corner then just redisplay the entire area of the - * image. This is a bit over-conservative, but we need to do - * something because a size change also means a position change. - */ - - if (((imgPtr->header.x2 - imgPtr->header.x1) != imgWidth) - || ((imgPtr->header.y2 - imgPtr->header.y1) != imgHeight)) { - x = y = 0; - width = imgWidth; - height = imgHeight; - Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1, - imgPtr->header.y1, imgPtr->header.x2, imgPtr->header.y2); - } - ComputeImageBbox(imgPtr->canvas, imgPtr); - Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1 + x, - imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width), - (int) (imgPtr->header.y1 + y + height)); -} diff --git a/generic/tkCanvLine.c b/generic/tkCanvLine.c deleted file mode 100644 index 20a9fb6..0000000 --- a/generic/tkCanvLine.c +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * tkCanvLine.c -- - * - * This file implements line items for canvas widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvLine.c,v 1.2 1998/09/14 18:23:05 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" - -/* - * The structure below defines the record for each line item. - */ - -typedef struct LineItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - Tk_Canvas canvas; /* Canvas containing item. Needed for - * parsing arrow shapes. */ - int numPoints; /* Number of points in line (always >= 2). */ - double *coordPtr; /* Pointer to malloc-ed array containing - * x- and y-coords of all points in line. - * X-coords are even-valued indices, y-coords - * are corresponding odd-valued indices. If - * the line has arrowheads then the first - * and last points have been adjusted to refer - * to the necks of the arrowheads rather than - * their tips. The actual endpoints are - * stored in the *firstArrowPtr and - * *lastArrowPtr, if they exist. */ - int width; /* Width of line. */ - XColor *fg; /* Foreground color for line. */ - Pixmap fillStipple; /* Stipple bitmap for filling line. */ - int capStyle; /* Cap style for line. */ - int joinStyle; /* Join style for line. */ - GC gc; /* Graphics context for filling line. */ - GC arrowGC; /* Graphics context for drawing arrowheads. */ - Tk_Uid arrow; /* Indicates whether or not to draw arrowheads: - * "none", "first", "last", or "both". */ - float arrowShapeA; /* Distance from tip of arrowhead to center. */ - float arrowShapeB; /* Distance from tip of arrowhead to trailing - * point, measured along shaft. */ - float arrowShapeC; /* Distance of trailing points from outside - * edge of shaft. */ - double *firstArrowPtr; /* Points to array of PTS_IN_ARROW points - * describing polygon for arrowhead at first - * point in line. First point of arrowhead - * is tip. Malloc'ed. NULL means no arrowhead - * at first point. */ - double *lastArrowPtr; /* Points to polygon for arrowhead at last - * point in line (PTS_IN_ARROW points, first - * of which is tip). Malloc'ed. NULL means - * no arrowhead at last point. */ - int smooth; /* Non-zero means draw line smoothed (i.e. - * with Bezier splines). */ - int splineSteps; /* Number of steps in each spline segment. */ -} LineItem; - -/* - * Number of points in an arrowHead: - */ - -#define PTS_IN_ARROW 6 - -/* - * Prototypes for procedures defined in this file: - */ - -static int ArrowheadPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, LineItem *linePtr, - double *arrowPtr)); -static void ComputeLineBbox _ANSI_ARGS_((Tk_Canvas canvas, - LineItem *linePtr)); -static int ConfigureLine _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas canvas, - LineItem *linePtr)); -static int CreateLine _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteLine _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayLine _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static int LineCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); -static int LineToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double LineToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *coordPtr)); -static int LineToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static int ParseArrowShape _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, - char *recordPtr, int offset)); -static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin, char *recordPtr, int offset, - Tcl_FreeProc **freeProcPtr)); -static void ScaleLine _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateLine _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * Information used for parsing configuration specs. If you change any - * of the default strings, be sure to change the corresponding default - * values in CreateLine. - */ - -static Tk_CustomOption arrowShapeOption = {ParseArrowShape, - PrintArrowShape, (ClientData) NULL}; -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, - "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL, - "8 10 3", Tk_Offset(LineItem, arrowShapeA), - TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption}, - {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL, - "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - "black", Tk_Offset(LineItem, fg), TK_CONFIG_NULL_OK}, - {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, - "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(LineItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, - "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(LineItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(LineItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * The structures below defines the line item type by means - * of procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkLineType = { - "line", /* name */ - sizeof(LineItem), /* itemSize */ - CreateLine, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureLine, /* configureProc */ - LineCoords, /* coordProc */ - DeleteLine, /* deleteProc */ - DisplayLine, /* displayProc */ - 0, /* alwaysRedraw */ - LineToPoint, /* pointProc */ - LineToArea, /* areaProc */ - LineToPostscript, /* postscriptProc */ - ScaleLine, /* scaleProc */ - TranslateLine, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - * The Tk_Uid's below refer to uids for the various arrow types: - */ - -static Tk_Uid noneUid = NULL; -static Tk_Uid firstUid = NULL; -static Tk_Uid lastUid = NULL; -static Tk_Uid bothUid = NULL; - -/* - * The definition below determines how large are static arrays - * used to hold spline points (splines larger than this have to - * have their arrays malloc-ed). - */ - -#define MAX_STATIC_POINTS 200 - -/* - *-------------------------------------------------------------- - * - * CreateLine -- - * - * This procedure is invoked to create a new line item in - * a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, - * so it can be safely freed by the caller. - * - * Side effects: - * A new line item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateLine(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing line. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - int i; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x1 y1 x2 y2 ?x3 y3 ...? ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Carry out initialization that is needed to set defaults and to - * allow proper cleanup after errors during the the remainder of - * this procedure. - */ - - linePtr->canvas = canvas; - linePtr->numPoints = 0; - linePtr->coordPtr = NULL; - linePtr->width = 1; - linePtr->fg = None; - linePtr->fillStipple = None; - linePtr->capStyle = CapButt; - linePtr->joinStyle = JoinRound; - linePtr->gc = None; - linePtr->arrowGC = None; - if (noneUid == NULL) { - noneUid = Tk_GetUid("none"); - firstUid = Tk_GetUid("first"); - lastUid = Tk_GetUid("last"); - bothUid = Tk_GetUid("both"); - } - linePtr->arrow = noneUid; - linePtr->arrowShapeA = (float)8.0; - linePtr->arrowShapeB = (float)10.0; - linePtr->arrowShapeC = (float)3.0; - linePtr->firstArrowPtr = NULL; - linePtr->lastArrowPtr = NULL; - linePtr->smooth = 0; - linePtr->splineSteps = 12; - - /* - * Count the number of points and then parse them into a point - * array. Leading arguments are assumed to be points if they - * start with a digit or a minus sign followed by a digit. - */ - - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') - || ((argv[i][1] != '.') && !isdigit(UCHAR(argv[i][1]))))) { - break; - } - } - if (LineCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { - goto error; - } - if (ConfigureLine(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { - return TCL_OK; - } - - error: - DeleteLine(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * LineCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on lines. See the user documentation for details - * on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -LineCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; - int i, numPoints; - - if (argc == 0) { - double *coordPtr; - int numCoords; - - numCoords = 2*linePtr->numPoints; - if (linePtr->firstArrowPtr != NULL) { - coordPtr = linePtr->firstArrowPtr; - } else { - coordPtr = linePtr->coordPtr; - } - for (i = 0; i < numCoords; i++, coordPtr++) { - if (i == 2) { - coordPtr = linePtr->coordPtr+2; - } - if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { - coordPtr = linePtr->lastArrowPtr; - } - Tcl_PrintDouble(interp, *coordPtr, buffer); - Tcl_AppendElement(interp, buffer); - } - } else if (argc < 4) { - Tcl_AppendResult(interp, - "too few coordinates for line: must have at least 4", - (char *) NULL); - return TCL_ERROR; - } else if (argc & 1) { - Tcl_AppendResult(interp, - "odd number of coordinates specified for line", - (char *) NULL); - return TCL_ERROR; - } else { - numPoints = argc/2; - if (linePtr->numPoints != numPoints) { - if (linePtr->coordPtr != NULL) { - ckfree((char *) linePtr->coordPtr); - } - linePtr->coordPtr = (double *) ckalloc((unsigned) - (sizeof(double) * argc)); - linePtr->numPoints = numPoints; - } - for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], - &linePtr->coordPtr[i]) != TCL_OK) { - return TCL_ERROR; - } - } - - /* - * Update arrowheads by throwing away any existing arrow-head - * information and calling ConfigureArrows to recompute it. - */ - - if (linePtr->firstArrowPtr != NULL) { - ckfree((char *) linePtr->firstArrowPtr); - linePtr->firstArrowPtr = NULL; - } - if (linePtr->lastArrowPtr != NULL) { - ckfree((char *) linePtr->lastArrowPtr); - linePtr->lastArrowPtr = NULL; - } - if (linePtr->arrow != noneUid) { - ConfigureArrows(canvas, linePtr); - } - ComputeLineBbox(canvas, linePtr); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureLine -- - * - * This procedure is invoked to configure various aspects - * of a line item such as its background color. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information, such as colors and stipple - * patterns, may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Line item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - XGCValues gcValues; - GC newGC, arrowGC; - unsigned long mask; - Tk_Window tkwin; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) linePtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as - * graphics contexts. - */ - - if (linePtr->fg == NULL) { - newGC = arrowGC = None; - } else { - gcValues.foreground = linePtr->fg->pixel; - gcValues.join_style = linePtr->joinStyle; - if (linePtr->width < 0) { - linePtr->width = 1; - } - gcValues.line_width = linePtr->width; - mask = GCForeground|GCJoinStyle|GCLineWidth; - if (linePtr->fillStipple != None) { - gcValues.stipple = linePtr->fillStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - if (linePtr->arrow == noneUid) { - gcValues.cap_style = linePtr->capStyle; - mask |= GCCapStyle; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - gcValues.line_width = 0; - arrowGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (linePtr->gc != None) { - Tk_FreeGC(Tk_Display(tkwin), linePtr->gc); - } - if (linePtr->arrowGC != None) { - Tk_FreeGC(Tk_Display(tkwin), linePtr->arrowGC); - } - linePtr->gc = newGC; - linePtr->arrowGC = arrowGC; - - /* - * Keep spline parameters within reasonable limits. - */ - - if (linePtr->splineSteps < 1) { - linePtr->splineSteps = 1; - } else if (linePtr->splineSteps > 100) { - linePtr->splineSteps = 100; - } - - /* - * Setup arrowheads, if needed. If arrowheads are turned off, - * restore the line's endpoints (they were shortened when the - * arrowheads were added). - */ - - if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != firstUid) - && (linePtr->arrow != bothUid)) { - linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; - linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; - ckfree((char *) linePtr->firstArrowPtr); - linePtr->firstArrowPtr = NULL; - } - if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { - int i; - - i = 2*(linePtr->numPoints-1); - linePtr->coordPtr[i] = linePtr->lastArrowPtr[0]; - linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1]; - ckfree((char *) linePtr->lastArrowPtr); - linePtr->lastArrowPtr = NULL; - } - if (linePtr->arrow != noneUid) { - if ((linePtr->arrow != firstUid) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { - Tcl_AppendResult(interp, "bad arrow spec \"", - linePtr->arrow, "\": must be none, first, last, or both", - (char *) NULL); - linePtr->arrow = noneUid; - return TCL_ERROR; - } - ConfigureArrows(canvas, linePtr); - } - - /* - * Recompute bounding box for line. - */ - - ComputeLineBbox(canvas, linePtr); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteLine -- - * - * This procedure is called to clean up the data structure - * associated with a line item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteLine(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - - if (linePtr->coordPtr != NULL) { - ckfree((char *) linePtr->coordPtr); - } - if (linePtr->fg != NULL) { - Tk_FreeColor(linePtr->fg); - } - if (linePtr->fillStipple != None) { - Tk_FreeBitmap(display, linePtr->fillStipple); - } - if (linePtr->gc != None) { - Tk_FreeGC(display, linePtr->gc); - } - if (linePtr->arrowGC != None) { - Tk_FreeGC(display, linePtr->arrowGC); - } - if (linePtr->firstArrowPtr != NULL) { - ckfree((char *) linePtr->firstArrowPtr); - } - if (linePtr->lastArrowPtr != NULL) { - ckfree((char *) linePtr->lastArrowPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeLineBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a line. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - -static void -ComputeLineBbox(canvas, linePtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - LineItem *linePtr; /* Item whose bbos is to be - * recomputed. */ -{ - double *coordPtr; - int i, width; - - coordPtr = linePtr->coordPtr; - linePtr->header.x1 = linePtr->header.x2 = (int) *coordPtr; - linePtr->header.y1 = linePtr->header.y2 = (int) coordPtr[1]; - - /* - * Compute the bounding box of all the points in the line, - * then expand in all directions by the line's width to take - * care of butting or rounded corners and projecting or - * rounded caps. This expansion is an overestimate (worst-case - * is square root of two over two) but it's simple. Don't do - * anything special for curves. This causes an additional - * overestimate in the bounding box, but is faster. - */ - - for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints; - i++, coordPtr += 2) { - TkIncludePoint((Tk_Item *) linePtr, coordPtr); - } - width = linePtr->width; - if (width < 1) { - width = 1; - } - linePtr->header.x1 -= width; - linePtr->header.x2 += width; - linePtr->header.y1 -= width; - linePtr->header.y2 += width; - - /* - * For mitered lines, make a second pass through all the points. - * Compute the locations of the two miter vertex points and add - * those into the bounding box. - */ - - if (linePtr->joinStyle == JoinMiter) { - for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3; - i--, coordPtr += 2) { - double miter[4]; - int j; - - if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) width, miter, miter+2)) { - for (j = 0; j < 4; j += 2) { - TkIncludePoint((Tk_Item *) linePtr, miter+j); - } - } - } - } - - /* - * Add in the sizes of arrowheads, if any. - */ - - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { - for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; - i++, coordPtr += 2) { - TkIncludePoint((Tk_Item *) linePtr, coordPtr); - } - } - if (linePtr->arrow != firstUid) { - for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; - i++, coordPtr += 2) { - TkIncludePoint((Tk_Item *) linePtr, coordPtr); - } - } - } - - /* - * Add one more pixel of fudge factor just to be safe (e.g. - * X may round differently than we do). - */ - - linePtr->header.x1 -= 1; - linePtr->header.x2 += 1; - linePtr->header.y1 -= 1; - linePtr->header.y2 += 1; -} - -/* - *-------------------------------------------------------------- - * - * DisplayLine -- - * - * This procedure is invoked to draw a line item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - XPoint staticPoints[MAX_STATIC_POINTS]; - XPoint *pointPtr; - XPoint *pPtr; - double *coordPtr; - int i, numPoints; - - if (linePtr->gc == None) { - return; - } - - /* - * Build up an array of points in screen coordinates. Use a - * static array unless the line has an enormous number of points; - * in this case, dynamically allocate an array. For smoothed lines, - * generate the curve points on each redisplay. - */ - - if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; - } else { - numPoints = linePtr->numPoints; - } - - if (numPoints <= MAX_STATIC_POINTS) { - pointPtr = staticPoints; - } else { - pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); - } - - if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, - linePtr->numPoints, linePtr->splineSteps, pointPtr, - (double *) NULL); - } else { - for (i = 0, coordPtr = linePtr->coordPtr, pPtr = pointPtr; - i < linePtr->numPoints; i += 1, coordPtr += 2, pPtr++) { - Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], - &pPtr->x, &pPtr->y); - } - } - - /* - * Display line, the free up line storage if it was dynamically - * allocated. If we're stippling, then modify the stipple offset - * in the GC. Be sure to reset the offset when done, since the - * GC is supposed to be read-only. - */ - - if (linePtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, linePtr->gc); - Tk_CanvasSetStippleOrigin(canvas, linePtr->arrowGC); - } - XDrawLines(display, drawable, linePtr->gc, pointPtr, numPoints, - CoordModeOrigin); - if (pointPtr != staticPoints) { - ckfree((char *) pointPtr); - } - - /* - * Display arrowheads, if they are wanted. - */ - - if (linePtr->firstArrowPtr != NULL) { - TkFillPolygon(canvas, linePtr->firstArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); - } - if (linePtr->lastArrowPtr != NULL) { - TkFillPolygon(canvas, linePtr->lastArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); - } - if (linePtr->fillStipple != None) { - XSetTSOrigin(display, linePtr->gc, 0, 0); - XSetTSOrigin(display, linePtr->arrowGC, 0, 0); - } -} - -/* - *-------------------------------------------------------------- - * - * LineToPoint -- - * - * Computes the distance from a given point to a given - * line, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are pointPtr[0] and pointPtr[1] is inside the line. If the - * point isn't inside the line then the return value is the - * distance from the point to the line. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -LineToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - double *coordPtr, *linePoints; - double staticSpace[2*MAX_STATIC_POINTS]; - double poly[10]; - double bestDist, dist; - int numPoints, count; - int changedMiterToBevel; /* Non-zero means that a mitered corner - * had to be treated as beveled after all - * because the angle was < 11 degrees. */ - - bestDist = 1.0e36; - - /* - * Handle smoothed lines by generating an expanded set of points - * against which to do the check. - */ - - if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; - if (numPoints <= MAX_STATIC_POINTS) { - linePoints = staticSpace; - } else { - linePoints = (double *) ckalloc((unsigned) - (2*numPoints*sizeof(double))); - } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, - linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, - linePoints); - } else { - numPoints = linePtr->numPoints; - linePoints = linePtr->coordPtr; - } - - /* - * The overall idea is to iterate through all of the edges of - * the line, computing a polygon for each edge and testing the - * point against that polygon. In addition, there are additional - * tests to deal with rounded joints and caps. - */ - - changedMiterToBevel = 0; - for (count = numPoints, coordPtr = linePoints; count >= 2; - count--, coordPtr += 2) { - - /* - * If rounding is done around the first point then compute - * the distance between the point and the point. - */ - - if (((linePtr->capStyle == CapRound) && (count == numPoints)) - || ((linePtr->joinStyle == JoinRound) - && (count != numPoints))) { - dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - - linePtr->width/2.0; - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - } - - /* - * Compute the polygonal shape corresponding to this edge, - * consisting of two points for the first point of the edge - * and two points for the last point of the edge. - */ - - if (count == numPoints) { - TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, - linePtr->capStyle == CapProjecting, poly, poly+2); - } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { - poly[0] = poly[6]; - poly[1] = poly[7]; - poly[2] = poly[4]; - poly[3] = poly[5]; - } else { - TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0, - poly, poly+2); - - /* - * If this line uses beveled joints, then check the distance - * to a polygon comprising the last two points of the previous - * polygon and the first two from this polygon; this checks - * the wedges that fill the mitered joint. - */ - - if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) { - poly[8] = poly[0]; - poly[9] = poly[1]; - dist = TkPolygonToPoint(poly, 5, pointPtr); - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - changedMiterToBevel = 0; - } - } - if (count == 2) { - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, - linePtr->capStyle == CapProjecting, poly+4, poly+6); - } else if (linePtr->joinStyle == JoinMiter) { - if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) linePtr->width, poly+4, poly+6) == 0) { - changedMiterToBevel = 1; - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, - 0, poly+4, poly+6); - } - } else { - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0, - poly+4, poly+6); - } - poly[8] = poly[0]; - poly[9] = poly[1]; - dist = TkPolygonToPoint(poly, 5, pointPtr); - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - } - - /* - * If caps are rounded, check the distance to the cap around the - * final end point of the line. - */ - - if (linePtr->capStyle == CapRound) { - dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - - linePtr->width/2.0; - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - } - - /* - * If there are arrowheads, check the distance to the arrowheads. - */ - - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { - dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW, - pointPtr); - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - } - if (linePtr->arrow != firstUid) { - dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW, - pointPtr); - if (dist <= 0.0) { - bestDist = 0.0; - goto done; - } else if (dist < bestDist) { - bestDist = dist; - } - } - } - - done: - if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { - ckfree((char *) linePoints); - } - return bestDist; -} - -/* - *-------------------------------------------------------------- - * - * LineToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangular area. - * - * Results: - * -1 is returned if the item is entirely outside the - * area, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -LineToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against line. */ - double *rectPtr; -{ - LineItem *linePtr = (LineItem *) itemPtr; - double staticSpace[2*MAX_STATIC_POINTS]; - double *linePoints; - int numPoints, result; - - /* - * Handle smoothed lines by generating an expanded set of points - * against which to do the check. - */ - - if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; - if (numPoints <= MAX_STATIC_POINTS) { - linePoints = staticSpace; - } else { - linePoints = (double *) ckalloc((unsigned) - (2*numPoints*sizeof(double))); - } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, - linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, - linePoints); - } else { - numPoints = linePtr->numPoints; - linePoints = linePtr->coordPtr; - } - - /* - * Check the segments of the line. - */ - - result = TkThickPolyLineToArea(linePoints, numPoints, - (double) linePtr->width, linePtr->capStyle, linePtr->joinStyle, - rectPtr); - if (result == 0) { - goto done; - } - - /* - * Check arrowheads, if any. - */ - - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { - if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW, - rectPtr) != result) { - result = 0; - goto done; - } - } - if (linePtr->arrow != firstUid) { - if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW, - rectPtr) != result) { - result = 0; - goto done; - } - } - } - - done: - if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { - ckfree((char *) linePoints); - } - return result; -} - -/* - *-------------------------------------------------------------- - * - * ScaleLine -- - * - * This procedure is invoked to rescale a line item. - * - * Results: - * None. - * - * Side effects: - * The line referred to by itemPtr is rescaled so that the - * following transformation is applied to all point - * coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing line. */ - Tk_Item *itemPtr; /* Line to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - double *coordPtr; - int i; - - /* - * Delete any arrowheads before scaling all the points (so that - * the end-points of the line get restored). - */ - - if (linePtr->firstArrowPtr != NULL) { - linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; - linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; - ckfree((char *) linePtr->firstArrowPtr); - linePtr->firstArrowPtr = NULL; - } - if (linePtr->lastArrowPtr != NULL) { - int i; - - i = 2*(linePtr->numPoints-1); - linePtr->coordPtr[i] = linePtr->lastArrowPtr[0]; - linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1]; - ckfree((char *) linePtr->lastArrowPtr); - linePtr->lastArrowPtr = NULL; - } - for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints; - i++, coordPtr += 2) { - coordPtr[0] = originX + scaleX*(*coordPtr - originX); - coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); - } - if (linePtr->arrow != noneUid) { - ConfigureArrows(canvas, linePtr); - } - ComputeLineBbox(canvas, linePtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateLine -- - * - * This procedure is called to move a line by a given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the line is offset by (xDelta, yDelta), and - * the bounding box is updated in the generic part of the item - * structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateLine(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - double *coordPtr; - int i; - - for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints; - i++, coordPtr += 2) { - coordPtr[0] += deltaX; - coordPtr[1] += deltaY; - } - if (linePtr->firstArrowPtr != NULL) { - for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; - i++, coordPtr += 2) { - coordPtr[0] += deltaX; - coordPtr[1] += deltaY; - } - } - if (linePtr->lastArrowPtr != NULL) { - for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; - i++, coordPtr += 2) { - coordPtr[0] += deltaX; - coordPtr[1] += deltaY; - } - } - ComputeLineBbox(canvas, linePtr); -} - -/* - *-------------------------------------------------------------- - * - * ParseArrowShape -- - * - * This procedure is called back during option parsing to - * parse arrow shape information. - * - * Results: - * The return value is a standard Tcl result: TCL_OK means - * that the arrow shape information was parsed ok, and - * TCL_ERROR means it couldn't be parsed. - * - * Side effects: - * Arrow information in recordPtr is updated. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) - ClientData clientData; /* Not used. */ - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Window tkwin; /* Not used. */ - char *value; /* Textual specification of arrow shape. */ - char *recordPtr; /* Pointer to item record in which to - * store arrow information. */ - int offset; /* Offset of shape information in widget - * record. */ -{ - LineItem *linePtr = (LineItem *) recordPtr; - double a, b, c; - int argc; - char **argv = NULL; - - if (offset != Tk_Offset(LineItem, arrowShapeA)) { - panic("ParseArrowShape received bogus offset"); - } - - if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { - syntaxError: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad arrow shape \"", value, - "\": must be list with three numbers", (char *) NULL); - if (argv != NULL) { - ckfree((char *) argv); - } - return TCL_ERROR; - } - if (argc != 3) { - goto syntaxError; - } - if ((Tk_CanvasGetCoord(interp, linePtr->canvas, argv[0], &a) != TCL_OK) - || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[1], &b) - != TCL_OK) - || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[2], &c) - != TCL_OK)) { - goto syntaxError; - } - linePtr->arrowShapeA = (float)a; - linePtr->arrowShapeB = (float)b; - linePtr->arrowShapeC = (float)c; - ckfree((char *) argv); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * PrintArrowShape -- - * - * This procedure is a callback invoked by the configuration - * code to return a printable value describing an arrow shape. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr) - ClientData clientData; /* Not used. */ - Tk_Window tkwin; /* Window associated with linePtr's widget. */ - char *recordPtr; /* Pointer to item record containing current - * shape information. */ - int offset; /* Offset of arrow information in record. */ - Tcl_FreeProc **freeProcPtr; /* Store address of procedure to call to - * free string here. */ -{ - LineItem *linePtr = (LineItem *) recordPtr; - char *buffer; - - buffer = (char *) ckalloc(120); - sprintf(buffer, "%.5g %.5g %.5g", linePtr->arrowShapeA, - linePtr->arrowShapeB, linePtr->arrowShapeC); - *freeProcPtr = TCL_DYNAMIC; - return buffer; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureArrows -- - * - * If arrowheads have been requested for a line, this - * procedure makes arrangements for the arrowheads. - * - * Results: - * Always returns TCL_OK. - * - * Side effects: - * Information in linePtr is set up for one or two arrowheads. - * the firstArrowPtr and lastArrowPtr polygons are allocated - * and initialized, if need be, and the end points of the line - * are adjusted so that a thick line doesn't stick out past - * the arrowheads. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ConfigureArrows(canvas, linePtr) - Tk_Canvas canvas; /* Canvas in which arrows will be - * displayed (interp and tkwin - * fields are needed). */ - LineItem *linePtr; /* Item to configure for arrows. */ -{ - double *poly, *coordPtr; - double dx, dy, length, sinTheta, cosTheta, temp; - double fracHeight; /* Line width as fraction of - * arrowhead width. */ - double backup; /* Distance to backup end points - * so the line ends in the middle - * of the arrowhead. */ - double vertX, vertY; /* Position of arrowhead vertex. */ - double shapeA, shapeB, shapeC; /* Adjusted coordinates (see - * explanation below). */ - - /* - * The code below makes a tiny increase in the shape parameters - * for the line. This is a bit of a hack, but it seems to result - * in displays that more closely approximate the specified parameters. - * Without the adjustment, the arrows come out smaller than expected. - */ - - shapeA = linePtr->arrowShapeA + 0.001; - shapeB = linePtr->arrowShapeB + 0.001; - shapeC = linePtr->arrowShapeC + linePtr->width/2.0 + 0.001; - - /* - * If there's an arrowhead on the first point of the line, compute - * its polygon and adjust the first point of the line so that the - * line doesn't stick out past the leading edge of the arrowhead. - */ - - fracHeight = (linePtr->width/2.0)/shapeC; - backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0; - if (linePtr->arrow != lastUid) { - poly = linePtr->firstArrowPtr; - if (poly == NULL) { - poly = (double *) ckalloc((unsigned) - (2*PTS_IN_ARROW*sizeof(double))); - poly[0] = poly[10] = linePtr->coordPtr[0]; - poly[1] = poly[11] = linePtr->coordPtr[1]; - linePtr->firstArrowPtr = poly; - } - dx = poly[0] - linePtr->coordPtr[2]; - dy = poly[1] - linePtr->coordPtr[3]; - length = hypot(dx, dy); - if (length == 0) { - sinTheta = cosTheta = 0.0; - } else { - sinTheta = dy/length; - cosTheta = dx/length; - } - vertX = poly[0] - shapeA*cosTheta; - vertY = poly[1] - shapeA*sinTheta; - temp = shapeC*sinTheta; - poly[2] = poly[0] - shapeB*cosTheta + temp; - poly[8] = poly[2] - 2*temp; - temp = shapeC*cosTheta; - poly[3] = poly[1] - shapeB*sinTheta - temp; - poly[9] = poly[3] + 2*temp; - poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); - poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); - poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); - poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); - - /* - * Polygon done. Now move the first point towards the second so - * that the corners at the end of the line are inside the - * arrowhead. - */ - - linePtr->coordPtr[0] = poly[0] - backup*cosTheta; - linePtr->coordPtr[1] = poly[1] - backup*sinTheta; - } - - /* - * Similar arrowhead calculation for the last point of the line. - */ - - if (linePtr->arrow != firstUid) { - coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2); - poly = linePtr->lastArrowPtr; - if (poly == NULL) { - poly = (double *) ckalloc((unsigned) - (2*PTS_IN_ARROW*sizeof(double))); - poly[0] = poly[10] = coordPtr[2]; - poly[1] = poly[11] = coordPtr[3]; - linePtr->lastArrowPtr = poly; - } - dx = poly[0] - coordPtr[0]; - dy = poly[1] - coordPtr[1]; - length = hypot(dx, dy); - if (length == 0) { - sinTheta = cosTheta = 0.0; - } else { - sinTheta = dy/length; - cosTheta = dx/length; - } - vertX = poly[0] - shapeA*cosTheta; - vertY = poly[1] - shapeA*sinTheta; - temp = shapeC*sinTheta; - poly[2] = poly[0] - shapeB*cosTheta + temp; - poly[8] = poly[2] - 2*temp; - temp = shapeC*cosTheta; - poly[3] = poly[1] - shapeB*sinTheta - temp; - poly[9] = poly[3] + 2*temp; - poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); - poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); - poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); - poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); - coordPtr[2] = poly[0] - backup*cosTheta; - coordPtr[3] = poly[1] - backup*sinTheta; - } - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * LineToPostscript -- - * - * This procedure is called to generate Postscript for - * line items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used - * to be there. If no error occurs, then Postscript for the - * item is appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -LineToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - LineItem *linePtr = (LineItem *) itemPtr; - char buffer[200]; - char *style; - - if (linePtr->fg == NULL) { - return TCL_OK; - } - - /* - * Generate a path for the line's center-line (do this differently - * for straight lines and smoothed lines). - */ - - if ((!linePtr->smooth) || (linePtr->numPoints <= 2)) { - Tk_CanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints); - } else { - if (linePtr->fillStipple == None) { - TkMakeBezierPostscript(interp, canvas, linePtr->coordPtr, - linePtr->numPoints); - } else { - /* - * Special hack: Postscript printers don't appear to be able - * to turn a path drawn with "curveto"s into a clipping path - * without exceeding resource limits, so TkMakeBezierPostscript - * won't work for stippled curves. Instead, generate all of - * the intermediate points here and output them into the - * Postscript file with "lineto"s instead. - */ - - double staticPoints[2*MAX_STATIC_POINTS]; - double *pointPtr; - int numPoints; - - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; - pointPtr = staticPoints; - if (numPoints > MAX_STATIC_POINTS) { - pointPtr = (double *) ckalloc((unsigned) - (numPoints * 2 * sizeof(double))); - } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, - linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, - pointPtr); - Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints); - if (pointPtr != staticPoints) { - ckfree((char *) pointPtr); - } - } - } - - /* - * Set other line-drawing parameters and stroke out the line. - */ - - sprintf(buffer, "%d setlinewidth\n", linePtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); - style = "0 setlinecap\n"; - if (linePtr->capStyle == CapRound) { - style = "1 setlinecap\n"; - } else if (linePtr->capStyle == CapProjecting) { - style = "2 setlinecap\n"; - } - Tcl_AppendResult(interp, style, (char *) NULL); - style = "0 setlinejoin\n"; - if (linePtr->joinStyle == JoinRound) { - style = "1 setlinejoin\n"; - } else if (linePtr->joinStyle == JoinBevel) { - style = "2 setlinejoin\n"; - } - Tcl_AppendResult(interp, style, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, linePtr->fg) != TCL_OK) { - return TCL_ERROR; - }; - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - - /* - * Output polygons for the arrowheads, if there are any. - */ - - if (linePtr->firstArrowPtr != NULL) { - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "grestore gsave\n", - (char *) NULL); - } - if (ArrowheadPostscript(interp, canvas, linePtr, - linePtr->firstArrowPtr) != TCL_OK) { - return TCL_ERROR; - } - } - if (linePtr->lastArrowPtr != NULL) { - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - } - if (ArrowheadPostscript(interp, canvas, linePtr, - linePtr->lastArrowPtr) != TCL_OK) { - return TCL_ERROR; - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ArrowheadPostscript -- - * - * This procedure is called to generate Postscript for - * an arrowhead for a line item. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used - * to be there. If no error occurs, then Postscript for the - * arrowhead is appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -ArrowheadPostscript(interp, canvas, linePtr, arrowPtr) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - LineItem *linePtr; /* Line item for which Postscript is - * being generated. */ - double *arrowPtr; /* Pointer to first of five points - * describing arrowhead polygon. */ -{ - Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - return TCL_OK; -} diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c deleted file mode 100644 index 5f18bc7..0000000 --- a/generic/tkCanvPoly.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * tkCanvPoly.c -- - * - * This file implements polygon items for canvas widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvPoly.c,v 1.2 1998/09/14 18:23:05 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" - -/* - * The structure below defines the record for each polygon item. - */ - -typedef struct PolygonItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - int numPoints; /* Number of points in polygon (always >= 3). - * Polygon is always closed. */ - int pointsAllocated; /* Number of points for which space is - * allocated at *coordPtr. */ - double *coordPtr; /* Pointer to malloc-ed array containing - * x- and y-coords of all points in polygon. - * X-coords are even-valued indices, y-coords - * are corresponding odd-valued indices. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ - GC outlineGC; /* Graphics context for drawing outline. */ - XColor *fillColor; /* Foreground color for polygon. */ - Pixmap fillStipple; /* Stipple bitmap for filling polygon. */ - GC fillGC; /* Graphics context for filling polygon. */ - int smooth; /* Non-zero means draw shape smoothed (i.e. - * with Bezier splines). */ - int splineSteps; /* Number of steps in each spline segment. */ - int autoClosed; /* Zero means the given polygon was closed, - one means that we auto closed it. */ -} PolygonItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, - "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas, - PolygonItem *polyPtr)); -static int ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static int PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); -static int PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); -static int PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static void ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * The structures below defines the polygon item type by means - * of procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkPolygonType = { - "polygon", /* name */ - sizeof(PolygonItem), /* itemSize */ - CreatePolygon, /* createProc */ - configSpecs, /* configSpecs */ - ConfigurePolygon, /* configureProc */ - PolygonCoords, /* coordProc */ - DeletePolygon, /* deleteProc */ - DisplayPolygon, /* displayProc */ - 0, /* alwaysRedraw */ - PolygonToPoint, /* pointProc */ - PolygonToArea, /* areaProc */ - PolygonToPostscript, /* postscriptProc */ - ScalePolygon, /* scaleProc */ - TranslatePolygon, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - * The definition below determines how large are static arrays - * used to hold spline points (splines larger than this have to - * have their arrays malloc-ed). - */ - -#define MAX_STATIC_POINTS 200 - -/* - *-------------------------------------------------------------- - * - * CreatePolygon -- - * - * This procedure is invoked to create a new polygon item in - * a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is - * left uninitialized, so it can be safely freed by the - * caller. - * - * Side effects: - * A new polygon item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreatePolygon(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing polygon. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - int i; - - if (argc < 6) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, - " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Carry out initialization that is needed in order to clean - * up after errors during the the remainder of this procedure. - */ - - polyPtr->numPoints = 0; - polyPtr->pointsAllocated = 0; - polyPtr->coordPtr = NULL; - polyPtr->width = 1; - polyPtr->outlineColor = NULL; - polyPtr->outlineGC = None; - polyPtr->fillColor = NULL; - polyPtr->fillStipple = None; - polyPtr->fillGC = None; - polyPtr->smooth = 0; - polyPtr->splineSteps = 12; - polyPtr->autoClosed = 0; - - /* - * Count the number of points and then parse them into a point - * array. Leading arguments are assumed to be points if they - * start with a digit or a minus sign followed by a digit. - */ - - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) { - break; - } - } - if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { - goto error; - } - - if (ConfigurePolygon(interp, canvas, itemPtr, argc-i, argv+i, 0) - == TCL_OK) { - return TCL_OK; - } - - error: - DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * PolygonCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on polygons. See the user documentation for details - * on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -PolygonCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; - int i, numPoints; - - if (argc == 0) { - /* - * Print the coords used to create the polygon. If we auto - * closed the polygon then we don't report the last point. - */ - for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) { - Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer); - Tcl_AppendElement(interp, buffer); - } - } else if (argc < 6) { - Tcl_AppendResult(interp, - "too few coordinates for polygon: must have at least 6", - (char *) NULL); - return TCL_ERROR; - } else if (argc & 1) { - Tcl_AppendResult(interp, - "odd number of coordinates specified for polygon", - (char *) NULL); - return TCL_ERROR; - } else { - numPoints = argc/2; - if (polyPtr->pointsAllocated <= numPoints) { - if (polyPtr->coordPtr != NULL) { - ckfree((char *) polyPtr->coordPtr); - } - - /* - * One extra point gets allocated here, just in case we have - * to add another point to close the polygon. - */ - - polyPtr->coordPtr = (double *) ckalloc((unsigned) - (sizeof(double) * (argc+2))); - polyPtr->pointsAllocated = numPoints+1; - } - for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], - &polyPtr->coordPtr[i]) != TCL_OK) { - return TCL_ERROR; - } - } - polyPtr->numPoints = numPoints; - polyPtr->autoClosed = 0; - - /* - * Close the polygon if it isn't already closed. - */ - - if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0]) - || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) { - polyPtr->autoClosed = 1; - polyPtr->numPoints++; - polyPtr->coordPtr[argc] = polyPtr->coordPtr[0]; - polyPtr->coordPtr[argc+1] = polyPtr->coordPtr[1]; - } - ComputePolygonBbox(canvas, polyPtr); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigurePolygon -- - * - * This procedure is invoked to configure various aspects - * of a polygon item such as its background color. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information, such as colors and stipple - * patterns, may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Polygon item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - XGCValues gcValues; - GC newGC; - unsigned long mask; - Tk_Window tkwin; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) polyPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as - * graphics contexts. - */ - - if (polyPtr->width < 1) { - polyPtr->width = 1; - } - if (polyPtr->outlineColor == NULL) { - newGC = None; - } else { - gcValues.foreground = polyPtr->outlineColor->pixel; - gcValues.line_width = polyPtr->width; - gcValues.cap_style = CapRound; - gcValues.join_style = JoinRound; - mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle; - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC); - } - polyPtr->outlineGC = newGC; - - if (polyPtr->fillColor == NULL) { - newGC = None; - } else { - gcValues.foreground = polyPtr->fillColor->pixel; - mask = GCForeground; - if (polyPtr->fillStipple != None) { - gcValues.stipple = polyPtr->fillStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (polyPtr->fillGC != None) { - Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC); - } - polyPtr->fillGC = newGC; - - /* - * Keep spline parameters within reasonable limits. - */ - - if (polyPtr->splineSteps < 1) { - polyPtr->splineSteps = 1; - } else if (polyPtr->splineSteps > 100) { - polyPtr->splineSteps = 100; - } - - ComputePolygonBbox(canvas, polyPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeletePolygon -- - * - * This procedure is called to clean up the data structure - * associated with a polygon item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeletePolygon(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - - if (polyPtr->coordPtr != NULL) { - ckfree((char *) polyPtr->coordPtr); - } - if (polyPtr->fillColor != NULL) { - Tk_FreeColor(polyPtr->fillColor); - } - if (polyPtr->fillStipple != None) { - Tk_FreeBitmap(display, polyPtr->fillStipple); - } - if (polyPtr->outlineColor != NULL) { - Tk_FreeColor(polyPtr->outlineColor); - } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(display, polyPtr->outlineGC); - } - if (polyPtr->fillGC != None) { - Tk_FreeGC(display, polyPtr->fillGC); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputePolygonBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a polygon. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - -static void -ComputePolygonBbox(canvas, polyPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - PolygonItem *polyPtr; /* Item whose bbox is to be - * recomputed. */ -{ - double *coordPtr; - int i; - - coordPtr = polyPtr->coordPtr; - polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr; - polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1]; - - for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints; - i++, coordPtr += 2) { - TkIncludePoint((Tk_Item *) polyPtr, coordPtr); - } - - /* - * Expand bounding box in all directions to account for the outline, - * which can stick out beyond the polygon. Add one extra pixel of - * fudge, just in case X rounds differently than we do. - */ - - i = (polyPtr->width+1)/2 + 1; - polyPtr->header.x1 -= i; - polyPtr->header.x2 += i; - polyPtr->header.y1 -= i; - polyPtr->header.y2 += i; -} - -/* - *-------------------------------------------------------------- - * - * TkFillPolygon -- - * - * This procedure is invoked to convert a polygon to screen - * coordinates and display it using a particular GC. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -void -TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC) - Tk_Canvas canvas; /* Canvas whose coordinate system - * is to be used for drawing. */ - double *coordPtr; /* Array of coordinates for polygon: - * x1, y1, x2, y2, .... */ - int numPoints; /* Twice this many coordinates are - * present at *coordPtr. */ - Display *display; /* Display on which to draw polygon. */ - Drawable drawable; /* Pixmap or window in which to draw - * polygon. */ - GC gc; /* Graphics context for drawing. */ - GC outlineGC; /* If not None, use this to draw an - * outline around the polygon after - * filling it. */ -{ - XPoint staticPoints[MAX_STATIC_POINTS]; - XPoint *pointPtr; - XPoint *pPtr; - int i; - - /* - * Build up an array of points in screen coordinates. Use a - * static array unless the polygon has an enormous number of points; - * in this case, dynamically allocate an array. - */ - - if (numPoints <= MAX_STATIC_POINTS) { - pointPtr = staticPoints; - } else { - pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); - } - - for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) { - Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x, - &pPtr->y); - } - - /* - * Display polygon, then free up polygon storage if it was dynamically - * allocated. - */ - - if (gc != None) { - XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex, - CoordModeOrigin); - } - if (outlineGC != None) { - XDrawLines(display, drawable, outlineGC, pointPtr, - numPoints, CoordModeOrigin); - } - if (pointPtr != staticPoints) { - ckfree((char *) pointPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * DisplayPolygon -- - * - * This procedure is invoked to draw a polygon item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - - if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) { - return; - } - - /* - * If we're stippling then modify the stipple offset in the GC. Be - * sure to reset the offset when done, since the GC is supposed to be - * read-only. - */ - - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { - Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC); - } - - if (!polyPtr->smooth) { - TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints, - display, drawable, polyPtr->fillGC, polyPtr->outlineGC); - } else { - int numPoints; - XPoint staticPoints[MAX_STATIC_POINTS]; - XPoint *pointPtr; - - /* - * This is a smoothed polygon. Display using a set of generated - * spline points rather than the original points. - */ - - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; - if (numPoints <= MAX_STATIC_POINTS) { - pointPtr = staticPoints; - } else { - pointPtr = (XPoint *) ckalloc((unsigned) - (numPoints * sizeof(XPoint))); - } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, - polyPtr->numPoints, polyPtr->splineSteps, pointPtr, - (double *) NULL); - if (polyPtr->fillGC != None) { - XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr, - numPoints, Complex, CoordModeOrigin); - } - if (polyPtr->outlineGC != None) { - XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr, - numPoints, CoordModeOrigin); - } - if (pointPtr != staticPoints) { - ckfree((char *) pointPtr); - } - } - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { - XSetTSOrigin(display, polyPtr->fillGC, 0, 0); - } -} - -/* - *-------------------------------------------------------------- - * - * PolygonToPoint -- - * - * Computes the distance from a given point to a given - * polygon, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are pointPtr[0] and pointPtr[1] is inside the polygon. If the - * point isn't inside the polygon then the return value is the - * distance from the point to the polygon. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -PolygonToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, distance; - double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints; - - if (!polyPtr->smooth) { - distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints, - pointPtr); - } else { - /* - * Smoothed polygon. Generate a new set of points and use them - * for comparison. - */ - - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; - if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; - } else { - coordPtr = (double *) ckalloc((unsigned) - (2*numPoints*sizeof(double))); - } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, - polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); - distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr); - if (coordPtr != staticSpace) { - ckfree((char *) coordPtr); - } - } - if (polyPtr->outlineColor != NULL) { - distance -= polyPtr->width/2.0; - if (distance < 0) { - distance = 0; - } - } - return distance; -} - -/* - *-------------------------------------------------------------- - * - * PolygonToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangular area. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -PolygonToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against polygon. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, rect2[4], halfWidth; - double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints, result; - - /* - * Handle smoothed polygons by generating an expanded set of points - * against which to do the check. - */ - - if (polyPtr->smooth) { - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; - if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; - } else { - coordPtr = (double *) ckalloc((unsigned) - (2*numPoints*sizeof(double))); - } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, - polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); - } else { - numPoints = polyPtr->numPoints; - coordPtr = polyPtr->coordPtr; - } - - if (polyPtr->width <= 1) { - /* - * The outline of the polygon doesn't stick out, so we can - * do a simple check. - */ - - result = TkPolygonToArea(coordPtr, numPoints, rectPtr); - } else { - /* - * The polygon has a wide outline, so the check is more complicated. - * First, check the line segments to see if they overlap the area. - */ - - result = TkThickPolyLineToArea(coordPtr, numPoints, - (double) polyPtr->width, CapRound, JoinRound, rectPtr); - if (result >= 0) { - goto done; - } - - /* - * There is no overlap between the polygon's outline and the - * rectangle. This means either the rectangle is entirely outside - * the polygon or entirely inside. To tell the difference, - * see whether the polygon (with 0 outline width) overlaps the - * rectangle bloated by half the outline width. - */ - - halfWidth = polyPtr->width/2.0; - rect2[0] = rectPtr[0] - halfWidth; - rect2[1] = rectPtr[1] - halfWidth; - rect2[2] = rectPtr[2] + halfWidth; - rect2[3] = rectPtr[3] + halfWidth; - if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) { - result = -1; - } else { - result = 0; - } - } - - done: - if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) { - ckfree((char *) coordPtr); - } - return result; -} - -/* - *-------------------------------------------------------------- - * - * ScalePolygon -- - * - * This procedure is invoked to rescale a polygon item. - * - * Results: - * None. - * - * Side effects: - * The polygon referred to by itemPtr is rescaled so that the - * following transformation is applied to all point - * coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing polygon. */ - Tk_Item *itemPtr; /* Polygon to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr; - int i; - - for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; - i++, coordPtr += 2) { - *coordPtr = originX + scaleX*(*coordPtr - originX); - coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); - } - ComputePolygonBbox(canvas, polyPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslatePolygon -- - * - * This procedure is called to move a polygon by a given - * amount. - * - * Results: - * None. - * - * Side effects: - * The position of the polygon is offset by (xDelta, yDelta), - * and the bounding box is updated in the generic part of the - * item structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslatePolygon(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr; - int i; - - for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; - i++, coordPtr += 2) { - *coordPtr += deltaX; - coordPtr[1] += deltaY; - } - ComputePolygonBbox(canvas, polyPtr); -} - -/* - *-------------------------------------------------------------- - * - * PolygonToPostscript -- - * - * This procedure is called to generate Postscript for - * polygon items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used - * to be there. If no error occurs, then Postscript for the - * item is appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -PolygonToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - char string[100]; - PolygonItem *polyPtr = (PolygonItem *) itemPtr; - - /* - * Fill the area of the polygon. - */ - - if (polyPtr->fillColor != NULL) { - if (!polyPtr->smooth) { - Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); - } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); - } - if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) { - return TCL_ERROR; - } - if (polyPtr->fillStipple != None) { - Tcl_AppendResult(interp, "eoclip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - if (polyPtr->outlineColor != NULL) { - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - } - } else { - Tcl_AppendResult(interp, "eofill\n", (char *) NULL); - } - } - - /* - * Now draw the outline, if there is one. - */ - - if (polyPtr->outlineColor != NULL) { - if (!polyPtr->smooth) { - Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); - } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); - } - - sprintf(string, "%d setlinewidth\n", polyPtr->width); - Tcl_AppendResult(interp, string, - "1 setlinecap\n1 setlinejoin\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor) - != TCL_OK) { - return TCL_ERROR; - } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - return TCL_OK; -} diff --git a/generic/tkCanvPs.c b/generic/tkCanvPs.c deleted file mode 100644 index 3b83d35..0000000 --- a/generic/tkCanvPs.c +++ /dev/null @@ -1,1386 +0,0 @@ -/* - * tkCanvPs.c -- - * - * This module provides Postscript output support for canvases, - * including the "postscript" widget command plus a few utility - * procedures used for generating Postscript. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvPs.c,v 1.3 1998/09/14 18:23:05 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkCanvas.h" -#include "tkPort.h" - -/* - * See tkCanvas.h for key data structures used to implement canvases. - */ - -/* - * One of the following structures is created to keep track of Postscript - * output being generated. It consists mostly of information provided on - * the widget command line. - */ - -typedef struct TkPostscriptInfo { - int x, y, width, height; /* Area to print, in canvas pixel - * coordinates. */ - int x2, y2; /* x+width and y+height. */ - char *pageXString; /* String value of "-pagex" option or NULL. */ - char *pageYString; /* String value of "-pagey" option or NULL. */ - double pageX, pageY; /* Postscript coordinates (in points) - * corresponding to pageXString and - * pageYString. Don't forget that y-values - * grow upwards for Postscript! */ - char *pageWidthString; /* Printed width of output. */ - char *pageHeightString; /* Printed height of output. */ - double scale; /* Scale factor for conversion: each pixel - * maps into this many points. */ - Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */ - int rotate; /* Non-zero means output should be rotated - * on page (landscape mode). */ - char *fontVar; /* If non-NULL, gives name of global variable - * containing font mapping information. - * Malloc'ed. */ - char *colorVar; /* If non-NULL, give name of global variable - * containing color mapping information. - * Malloc'ed. */ - char *colorMode; /* Mode for handling colors: "monochrome", - * "gray", or "color". Malloc'ed. */ - int colorLevel; /* Numeric value corresponding to colorMode: - * 0 for mono, 1 for gray, 2 for color. */ - char *fileName; /* Name of file in which to write Postscript; - * NULL means return Postscript info as - * result. Malloc'ed. */ - char *channelName; /* If -channel is specified, the name of - * the channel to use. */ - Tcl_Channel chan; /* Open channel corresponding to fileName. */ - Tcl_HashTable fontTable; /* Hash table containing names of all font - * families used in output. The hash table - * values are not used. */ - int prepass; /* Non-zero means that we're currently in - * the pre-pass that collects font information, - * so the Postscript generated isn't - * relevant. */ -} TkPostscriptInfo; - -/* - * The table below provides a template that's used to process arguments - * to the canvas "postscript" command and fill in TkPostscriptInfo - * structures. - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, colorVar), 0}, - {TK_CONFIG_STRING, "-colormode", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, colorMode), 0}, - {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, fileName), 0}, - {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, channelName), 0}, - {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, fontVar), 0}, - {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, height), 0}, - {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, pageAnchor), 0}, - {TK_CONFIG_STRING, "-pageheight", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, pageHeightString), 0}, - {TK_CONFIG_STRING, "-pagewidth", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, pageWidthString), 0}, - {TK_CONFIG_STRING, "-pagex", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, pageXString), 0}, - {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, pageYString), 0}, - {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, rotate), 0}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, width), 0}, - {TK_CONFIG_PIXELS, "-x", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, x), 0}, - {TK_CONFIG_PIXELS, "-y", (char *) NULL, (char *) NULL, - "", Tk_Offset(TkPostscriptInfo, y), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * The prolog data. Generated by str2c from prolog.ps - * This was split in small chunks by str2c because - * some C compiler have limitations on the size of static strings. - */ -static CONST char * CONST prolog[]= { - /* Start of part 1 (2000 characters) */ - "%%BeginProlog\n\ -50 dict begin\n\ -\n\ -% This is a standard prolog for Postscript generated by Tk's canvas\n\ -% widget.\n\ -% RCS: @(#) $Id: tkCanvPs.c,v 1.3 1998/09/14 18:23:05 stanton Exp $ -\n\ -% The definitions below just define all of the variables used in\n\ -% any of the procedures here. This is needed for obscure reasons\n\ -% explained on p. 716 of the Postscript manual (Section H.2.7,\n\ -% \"Initializing Variables,\" in the section on Encapsulated Postscript).\n\ -\n\ -/baseline 0 def\n\ -/stipimage 0 def\n\ -/height 0 def\n\ -/justify 0 def\n\ -/lineLength 0 def\n\ -/spacing 0 def\n\ -/stipple 0 def\n\ -/strings 0 def\n\ -/xoffset 0 def\n\ -/yoffset 0 def\n\ -/tmpstip null def\n\ -\n\ -% Define the array ISOLatin1Encoding (which specifies how characters are\n\ -% encoded for ISO-8859-1 fonts), if it isn't already present (Postscript\n\ -% level 2 is supposed to define it, but level 1 doesn't).\n\ -\n\ -systemdict /ISOLatin1Encoding known not {\n\ - /ISOLatin1Encoding [\n\ - /space /space /space /space /space /space /space /space\n\ - /space /space /space /space /space /space /space /space\n\ - /space /space /space /space /space /space /space /space\n\ - /space /space /space /space /space /space /space /space\n\ - /space /exclam /quotedbl /numbersign /dollar /percent /ampersand\n\ - /quoteright\n\ - /parenleft /parenright /asterisk /plus /comma /minus /period /slash\n\ - /zero /one /two /three /four /five /six /seven\n\ - /eight /nine /colon /semicolon /less /equal /greater /question\n\ - /at /A /B /C /D /E /F /G\n\ - /H /I /J /K /L /M /N /O\n\ - /P /Q /R /S /T /U /V /W\n\ - /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n\ - /quoteleft /a /b /c /d /e /f /g\n\ - /h /i /j /k /l /m /n /o\n\ - /p /q /r /s /t /u /v /w\n\ - /x /y /z /braceleft /bar /braceright /asciitilde /space\n\ - /space /space /space /space /space /space /space /space\n\ - /space /space /space /space /space /space /space /space\n\ - /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n\ - /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron\n\ - /space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n\ - /dieresis /copyright /ordfem", - /* End of part 1 */ - - /* Start of part 2 (2000 characters) */ - "inine /guillemotleft /logicalnot /hyphen\n\ - /registered /macron\n\ - /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph\n\ - /periodcentered\n\ - /cedillar /onesuperior /ordmasculine /guillemotright /onequarter\n\ - /onehalf /threequarters /questiondown\n\ - /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n\ - /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex\n\ - /Idieresis\n\ - /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n\ - /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n\ - /germandbls\n\ - /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n\ - /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex\n\ - /idieresis\n\ - /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n\ - /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn\n\ - /ydieresis\n\ - ] def\n\ -} if\n\ -\n\ -% font ISOEncode font\n\ -% This procedure changes the encoding of a font from the default\n\ -% Postscript encoding to ISOLatin1. It's typically invoked just\n\ -% before invoking \"setfont\". The body of this procedure comes from\n\ -% Section 5.6.1 of the Postscript book.\n\ -\n\ -/ISOEncode {\n\ - dup length dict begin\n\ - {1 index /FID ne {def} {pop pop} ifelse} forall\n\ - /Encoding ISOLatin1Encoding def\n\ - currentdict\n\ - end\n\ -\n\ - % I'm not sure why it's necessary to use \"definefont\" on this new\n\ - % font, but it seems to be important; just use the name \"Temporary\"\n\ - % for the font.\n\ -\n\ - /Temporary exch definefont\n\ -} bind def\n\ -\n\ -% StrokeClip\n\ -%\n\ -% This procedure converts the current path into a clip area under\n\ -% the assumption of stroking. It's a bit tricky because some Postscript\n\ -% interpreters get errors during strokepath for dashed lines. If\n\ -% this happens then turn off dashes and try again.\n\ -\n\ -/StrokeClip {\n\ - {strokepath} stopped {\n\ - (This Postscript printer gets limitcheck overflows when) =\n\ - (stippling dashed lines; lines will be printed solid instead.) =\n\ - [] 0 setdash strokepath} if\n\ - clip\n\ -} bind def\n\ -\n\ -% d", - /* End of part 2 */ - - /* Start of part 3 (2000 characters) */ - "esiredSize EvenPixels closestSize\n\ -%\n\ -% The procedure below is used for stippling. Given the optimal size\n\ -% of a dot in a stipple pattern in the current user coordinate system,\n\ -% compute the closest size that is an exact multiple of the device's\n\ -% pixel size. This allows stipple patterns to be displayed without\n\ -% aliasing effects.\n\ -\n\ -/EvenPixels {\n\ - % Compute exact number of device pixels per stipple dot.\n\ - dup 0 matrix currentmatrix dtransform\n\ - dup mul exch dup mul add sqrt\n\ -\n\ - % Round to an integer, make sure the number is at least 1, and compute\n\ - % user coord distance corresponding to this.\n\ - dup round dup 1 lt {pop 1} if\n\ - exch div mul\n\ -} bind def\n\ -\n\ -% width height string StippleFill --\n\ -%\n\ -% Given a path already set up and a clipping region generated from\n\ -% it, this procedure will fill the clipping region with a stipple\n\ -% pattern. \"String\" contains a proper image description of the\n\ -% stipple pattern and \"width\" and \"height\" give its dimensions. Each\n\ -% stipple dot is assumed to be about one unit across in the current\n\ -% user coordinate system. This procedure trashes the graphics state.\n\ -\n\ -/StippleFill {\n\ - % The following code is needed to work around a NeWSprint bug.\n\ -\n\ - /tmpstip 1 index def\n\ -\n\ - % Change the scaling so that one user unit in user coordinates\n\ - % corresponds to the size of one stipple dot.\n\ - 1 EvenPixels dup scale\n\ -\n\ - % Compute the bounding box occupied by the path (which is now\n\ - % the clipping region), and round the lower coordinates down\n\ - % to the nearest starting point for the stipple pattern. Be\n\ - % careful about negative numbers, since the rounding works\n\ - % differently on them.\n\ -\n\ - pathbbox\n\ - 4 2 roll\n\ - 5 index div dup 0 lt {1 sub} if cvi 5 index mul 4 1 roll\n\ - 6 index div dup 0 lt {1 sub} if cvi 6 index mul 3 2 roll\n\ -\n\ - % Stack now: width height string y1 y2 x1 x2\n\ - % Below is a doubly-nested for loop to iterate across this area\n\ - % in units of the stipple pattern size, going up columns then\n\ - % acr", - /* End of part 3 */ - - /* Start of part 4 (2000 characters) */ - "oss rows, blasting out a stipple-pattern-sized rectangle at\n\ - % each position\n\ -\n\ - 6 index exch {\n\ - 2 index 5 index 3 index {\n\ - % Stack now: width height string y1 y2 x y\n\ -\n\ - gsave\n\ - 1 index exch translate\n\ - 5 index 5 index true matrix tmpstip imagemask\n\ - grestore\n\ - } for\n\ - pop\n\ - } for\n\ - pop pop pop pop pop\n\ -} bind def\n\ -\n\ -% -- AdjustColor --\n\ -% Given a color value already set for output by the caller, adjusts\n\ -% that value to a grayscale or mono value if requested by the CL\n\ -% variable.\n\ -\n\ -/AdjustColor {\n\ - CL 2 lt {\n\ - currentgray\n\ - CL 0 eq {\n\ - .5 lt {0} {1} ifelse\n\ - } if\n\ - setgray\n\ - } if\n\ -} bind def\n\ -\n\ -% x y strings spacing xoffset yoffset justify stipple DrawText --\n\ -% This procedure does all of the real work of drawing text. The\n\ -% color and font must already have been set by the caller, and the\n\ -% following arguments must be on the stack:\n\ -%\n\ -% x, y - Coordinates at which to draw text.\n\ -% strings - An array of strings, one for each line of the text item,\n\ -% in order from top to bottom.\n\ -% spacing - Spacing between lines.\n\ -% xoffset - Horizontal offset for text bbox relative to x and y: 0 for\n\ -% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se.\n\ -% yoffset - Vertical offset for text bbox relative to x and y: 0 for\n\ -% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se.\n\ -% justify - 0 for left justification, 0.5 for center, 1 for right justify.\n\ -% stipple - Boolean value indicating whether or not text is to be\n\ -% drawn in stippled fashion. If text is stippled,\n\ -% procedure StippleText must have been defined to call\n\ -% StippleFill in the right way.\n\ -%\n\ -% Also, when this procedure is invoked, the color and font must already\n\ -% have been set for the text.\n\ -\n\ -/DrawText {\n\ - /stipple exch def\n\ - /justify exch def\n\ - /yoffset exch def\n\ - /xoffset exch def\n\ - /spacing exch def\n\ - /strings exch def\n\ -\n\ - % First scan through all of the text to find the widest line.\n\ -\n\ - /lineLength 0 def\n\ - strings {\n\ - stringwidth pop\n\ - dup lineLength gt {/lineLength exch def}", - /* End of part 4 */ - - /* Start of part 5 (1546 characters) */ - " {pop} ifelse\n\ - newpath\n\ - } forall\n\ -\n\ - % Compute the baseline offset and the actual font height.\n\ -\n\ - 0 0 moveto (TXygqPZ) false charpath\n\ - pathbbox dup /baseline exch def\n\ - exch pop exch sub /height exch def pop\n\ - newpath\n\ -\n\ - % Translate coordinates first so that the origin is at the upper-left\n\ - % corner of the text's bounding box. Remember that x and y for\n\ - % positioning are still on the stack.\n\ -\n\ - translate\n\ - lineLength xoffset mul\n\ - strings length 1 sub spacing mul height add yoffset mul translate\n\ -\n\ - % Now use the baseline and justification information to translate so\n\ - % that the origin is at the baseline and positioning point for the\n\ - % first line of text.\n\ -\n\ - justify lineLength mul baseline neg translate\n\ -\n\ - % Iterate over each of the lines to output it. For each line,\n\ - % compute its width again so it can be properly justified, then\n\ - % display it.\n\ -\n\ - strings {\n\ - dup stringwidth pop\n\ - justify neg mul 0 moveto\n\ - stipple {\n\ -\n\ - % The text is stippled, so turn it into a path and print\n\ - % by calling StippledText, which in turn calls StippleFill.\n\ - % Unfortunately, many Postscript interpreters will get\n\ - % overflow errors if we try to do the whole string at\n\ - % once, so do it a character at a time.\n\ -\n\ - gsave\n\ - /char (X) def\n\ - {\n\ - char 0 3 -1 roll put\n\ - currentpoint\n\ - gsave\n\ - char true charpath clip StippleText\n\ - grestore\n\ - char stringwidth translate\n\ - moveto\n\ - } forall\n\ - grestore\n\ - } {show} ifelse\n\ - 0 spacing neg translate\n\ - } forall\n\ -} bind def\n\ -\n\ -%%EndProlog\n\ -", - /* End of part 5 */ - - NULL /* End of data marker */ -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int GetPostscriptPoints _ANSI_ARGS_((Tcl_Interp *interp, - char *string, double *doublePtr)); - -/* - *-------------------------------------------------------------- - * - * TkCanvPostscriptCmd -- - * - * This procedure is invoked to process the "postscript" options - * of the widget command for canvas widgets. See the user - * documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) - TkCanvas *canvasPtr; /* Information about canvas widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Caller has - * already parsed this command enough - * to know that argv[1] is - * "postscript". */ -{ - TkPostscriptInfo psInfo, *oldInfoPtr; - int result; - Tk_Item *itemPtr; -#define STRING_LENGTH 400 - char string[STRING_LENGTH+1], *p; - time_t now; - size_t length; - int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of - * area to be marked up, measured - * in canvas units from the positioning - * point on the page (reflects - * anchor position). Initial values - * needed only to stop compiler - * warnings. */ - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - Tcl_DString buffer; - CONST char * CONST *chunk; - - /* - *---------------------------------------------------------------- - * Initialize the data structure describing Postscript generation, - * then process all the arguments to fill the data structure in. - *---------------------------------------------------------------- - */ - - oldInfoPtr = canvasPtr->psInfoPtr; - canvasPtr->psInfoPtr = &psInfo; - psInfo.x = canvasPtr->xOrigin; - psInfo.y = canvasPtr->yOrigin; - psInfo.width = -1; - psInfo.height = -1; - psInfo.pageXString = NULL; - psInfo.pageYString = NULL; - psInfo.pageX = 72*4.25; - psInfo.pageY = 72*5.5; - psInfo.pageWidthString = NULL; - psInfo.pageHeightString = NULL; - psInfo.scale = 1.0; - psInfo.pageAnchor = TK_ANCHOR_CENTER; - psInfo.rotate = 0; - psInfo.fontVar = NULL; - psInfo.colorVar = NULL; - psInfo.colorMode = NULL; - psInfo.colorLevel = 0; - psInfo.fileName = NULL; - psInfo.channelName = NULL; - psInfo.chan = NULL; - psInfo.prepass = 0; - Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); - result = Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, - configSpecs, argc-2, argv+2, (char *) &psInfo, - TK_CONFIG_ARGV_ONLY); - if (result != TCL_OK) { - goto cleanup; - } - - if (psInfo.width == -1) { - psInfo.width = Tk_Width(canvasPtr->tkwin); - } - if (psInfo.height == -1) { - psInfo.height = Tk_Height(canvasPtr->tkwin); - } - psInfo.x2 = psInfo.x + psInfo.width; - psInfo.y2 = psInfo.y + psInfo.height; - - if (psInfo.pageXString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageXString, - &psInfo.pageX) != TCL_OK) { - goto cleanup; - } - } - if (psInfo.pageYString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageYString, - &psInfo.pageY) != TCL_OK) { - goto cleanup; - } - } - if (psInfo.pageWidthString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageWidthString, - &psInfo.scale) != TCL_OK) { - goto cleanup; - } - psInfo.scale /= psInfo.width; - } else if (psInfo.pageHeightString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageHeightString, - &psInfo.scale) != TCL_OK) { - goto cleanup; - } - psInfo.scale /= psInfo.height; - } else { - psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(canvasPtr->tkwin)); - psInfo.scale /= WidthOfScreen(Tk_Screen(canvasPtr->tkwin)); - } - switch (psInfo.pageAnchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_W: - case TK_ANCHOR_SW: - deltaX = 0; - break; - case TK_ANCHOR_N: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_S: - deltaX = -psInfo.width/2; - break; - case TK_ANCHOR_NE: - case TK_ANCHOR_E: - case TK_ANCHOR_SE: - deltaX = -psInfo.width; - break; - } - switch (psInfo.pageAnchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_N: - case TK_ANCHOR_NE: - deltaY = - psInfo.height; - break; - case TK_ANCHOR_W: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_E: - deltaY = -psInfo.height/2; - break; - case TK_ANCHOR_SW: - case TK_ANCHOR_S: - case TK_ANCHOR_SE: - deltaY = 0; - break; - } - - if (psInfo.colorMode == NULL) { - psInfo.colorLevel = 2; - } else { - length = strlen(psInfo.colorMode); - if (strncmp(psInfo.colorMode, "monochrome", length) == 0) { - psInfo.colorLevel = 0; - } else if (strncmp(psInfo.colorMode, "gray", length) == 0) { - psInfo.colorLevel = 1; - } else if (strncmp(psInfo.colorMode, "color", length) == 0) { - psInfo.colorLevel = 2; - } else { - Tcl_AppendResult(canvasPtr->interp, "bad color mode \"", - psInfo.colorMode, "\": must be monochrome, ", - "gray, or color", (char *) NULL); - goto cleanup; - } - } - - if (psInfo.fileName != NULL) { - - /* - * Check that -file and -channel are not both specified. - */ - - if (psInfo.channelName != NULL) { - Tcl_AppendResult(canvasPtr->interp, "can't specify both -file", - " and -channel", (char *) NULL); - result = TCL_ERROR; - goto cleanup; - } - - /* - * Check that we are not in a safe interpreter. If we are, disallow - * the -file specification. - */ - - if (Tcl_IsSafe(canvasPtr->interp)) { - Tcl_AppendResult(canvasPtr->interp, "can't specify -file in a", - " safe interpreter", (char *) NULL); - result = TCL_ERROR; - goto cleanup; - } - - p = Tcl_TranslateFileName(canvasPtr->interp, psInfo.fileName, &buffer); - if (p == NULL) { - goto cleanup; - } - psInfo.chan = Tcl_OpenFileChannel(canvasPtr->interp, p, "w", 0666); - Tcl_DStringFree(&buffer); - if (psInfo.chan == NULL) { - goto cleanup; - } - } - - if (psInfo.channelName != NULL) { - int mode; - - /* - * Check that the channel is found in this interpreter and that it - * is open for writing. - */ - - psInfo.chan = Tcl_GetChannel(canvasPtr->interp, psInfo.channelName, - &mode); - if (psInfo.chan == (Tcl_Channel) NULL) { - result = TCL_ERROR; - goto cleanup; - } - if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(canvasPtr->interp, "channel \"", - psInfo.channelName, "\" wasn't opened for writing", - (char *) NULL); - result = TCL_ERROR; - goto cleanup; - } - } - - /* - *-------------------------------------------------------- - * Make a pre-pass over all of the items, generating Postscript - * and then throwing it away. The purpose of this pass is just - * to collect information about all the fonts in use, so that - * we can output font information in the proper form required - * by the Document Structuring Conventions. - *-------------------------------------------------------- - */ - - psInfo.prepass = 1; - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x) - || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) { - continue; - } - if (itemPtr->typePtr->postscriptProc == NULL) { - continue; - } - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, - (Tk_Canvas) canvasPtr, itemPtr, 1); - Tcl_ResetResult(canvasPtr->interp); - if (result != TCL_OK) { - /* - * An error just occurred. Just skip out of this loop. - * There's no need to report the error now; it can be - * reported later (errors can happen later that don't - * happen now, so we still have to check for errors later - * anyway). - */ - break; - } - } - psInfo.prepass = 0; - - /* - *-------------------------------------------------------- - * Generate the header and prolog for the Postscript. - *-------------------------------------------------------- - */ - - Tcl_AppendResult(canvasPtr->interp, "%!PS-Adobe-3.0 EPSF-3.0\n", - "%%Creator: Tk Canvas Widget\n", (char *) NULL); -#if !(defined(__WIN32__) || defined(MAC_TCL)) - if (!Tcl_IsSafe(interp)) { - struct passwd *pwPtr = getpwuid(getuid()); - Tcl_AppendResult(canvasPtr->interp, "%%For: ", - (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "\n", - (char *) NULL); - endpwent(); - } -#endif /* __WIN32__ || MAC_TCL */ - Tcl_AppendResult(canvasPtr->interp, "%%Title: Window ", - Tk_PathName(canvasPtr->tkwin), "\n", (char *) NULL); - time(&now); - Tcl_AppendResult(canvasPtr->interp, "%%CreationDate: ", - ctime(&now), (char *) NULL); - if (!psInfo.rotate) { - sprintf(string, "%d %d %d %d", - (int) (psInfo.pageX + psInfo.scale*deltaX), - (int) (psInfo.pageY + psInfo.scale*deltaY), - (int) (psInfo.pageX + psInfo.scale*(deltaX + psInfo.width) - + 1.0), - (int) (psInfo.pageY + psInfo.scale*(deltaY + psInfo.height) - + 1.0)); - } else { - sprintf(string, "%d %d %d %d", - (int) (psInfo.pageX - psInfo.scale*(deltaY + psInfo.height)), - (int) (psInfo.pageY + psInfo.scale*deltaX), - (int) (psInfo.pageX - psInfo.scale*deltaY + 1.0), - (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) - + 1.0)); - } - Tcl_AppendResult(canvasPtr->interp, "%%BoundingBox: ", string, - "\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Pages: 1\n", - "%%DocumentData: Clean7Bit\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Orientation: ", - psInfo.rotate ? "Landscape\n" : "Portrait\n", (char *) NULL); - p = "%%DocumentNeededResources: font "; - for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, p, - Tcl_GetHashKey(&psInfo.fontTable, hPtr), - "\n", (char *) NULL); - p = "%%+ font "; - } - Tcl_AppendResult(canvasPtr->interp, "%%EndComments\n\n", (char *) NULL); - - /* - * Insert the prolog - */ - for (chunk=prolog; *chunk; chunk++) { - Tcl_AppendResult(interp, *chunk, (char *) NULL); - } - - if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); - Tcl_ResetResult(canvasPtr->interp); - } - - /* - *----------------------------------------------------------- - * Document setup: set the color level and include fonts. - *----------------------------------------------------------- - */ - - sprintf(string, "/CL %d def\n", psInfo.colorLevel); - Tcl_AppendResult(canvasPtr->interp, "%%BeginSetup\n", string, - (char *) NULL); - for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, "%%IncludeResource: font ", - Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", (char *) NULL); - } - Tcl_AppendResult(canvasPtr->interp, "%%EndSetup\n\n", (char *) NULL); - - /* - *----------------------------------------------------------- - * Page setup: move to page positioning point, rotate if - * needed, set scale factor, offset for proper anchor position, - * and set clip region. - *----------------------------------------------------------- - */ - - Tcl_AppendResult(canvasPtr->interp, "%%Page: 1 1\n", "save\n", - (char *) NULL); - sprintf(string, "%.1f %.1f translate\n", psInfo.pageX, psInfo.pageY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); - if (psInfo.rotate) { - Tcl_AppendResult(canvasPtr->interp, "90 rotate\n", (char *) NULL); - } - sprintf(string, "%.4g %.4g scale\n", psInfo.scale, psInfo.scale); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); - sprintf(string, "%d %d translate\n", deltaX - psInfo.x, deltaY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); - sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2), - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2)); - Tcl_AppendResult(canvasPtr->interp, string, - " lineto closepath clip newpath\n", (char *) NULL); - if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); - Tcl_ResetResult(canvasPtr->interp); - } - - /* - *--------------------------------------------------------------------- - * Iterate through all the items, having each relevant one draw itself. - * Quit if any of the items returns an error. - *--------------------------------------------------------------------- - */ - - result = TCL_OK; - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x) - || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) { - continue; - } - if (itemPtr->typePtr->postscriptProc == NULL) { - continue; - } - Tcl_AppendResult(canvasPtr->interp, "gsave\n", (char *) NULL); - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, - (Tk_Canvas) canvasPtr, itemPtr, 0); - if (result != TCL_OK) { - char msg[100]; - - sprintf(msg, "\n (generating Postscript for item %d)", - itemPtr->id); - Tcl_AddErrorInfo(canvasPtr->interp, msg); - goto cleanup; - } - Tcl_AppendResult(canvasPtr->interp, "grestore\n", (char *) NULL); - if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); - Tcl_ResetResult(canvasPtr->interp); - } - } - - /* - *--------------------------------------------------------------------- - * Output page-end information, such as commands to print the page - * and document trailer stuff. - *--------------------------------------------------------------------- - */ - - Tcl_AppendResult(canvasPtr->interp, "restore showpage\n\n", - "%%Trailer\nend\n%%EOF\n", (char *) NULL); - if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); - Tcl_ResetResult(canvasPtr->interp); - } - - /* - * Clean up psInfo to release malloc'ed stuff. - */ - - cleanup: - if (psInfo.pageXString != NULL) { - ckfree(psInfo.pageXString); - } - if (psInfo.pageYString != NULL) { - ckfree(psInfo.pageYString); - } - if (psInfo.pageWidthString != NULL) { - ckfree(psInfo.pageWidthString); - } - if (psInfo.pageHeightString != NULL) { - ckfree(psInfo.pageHeightString); - } - if (psInfo.fontVar != NULL) { - ckfree(psInfo.fontVar); - } - if (psInfo.colorVar != NULL) { - ckfree(psInfo.colorVar); - } - if (psInfo.colorMode != NULL) { - ckfree(psInfo.colorMode); - } - if (psInfo.fileName != NULL) { - ckfree(psInfo.fileName); - } - if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { - Tcl_Close(canvasPtr->interp, psInfo.chan); - } - if (psInfo.channelName != NULL) { - ckfree(psInfo.channelName); - } - Tcl_DeleteHashTable(&psInfo.fontTable); - canvasPtr->psInfoPtr = oldInfoPtr; - return result; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsColor -- - * - * This procedure is called by individual canvas items when - * they want to set a color value for output. Given information - * about an X color, this procedure will generate Postscript - * commands to set up an appropriate color in Postscript. - * - * Results: - * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. - * If no error occurs, then additional Postscript will be - * appended to interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasPsColor(interp, canvas, colorPtr) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ - XColor *colorPtr; /* Information about color. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; - int tmp; - double red, green, blue; - char string[200]; - - if (psInfoPtr->prepass) { - return TCL_OK; - } - - /* - * If there is a color map defined, then look up the color's name - * in the map and use the Postscript commands found there, if there - * are any. - */ - - if (psInfoPtr->colorVar != NULL) { - char *cmdString; - - cmdString = Tcl_GetVar2(interp, psInfoPtr->colorVar, - Tk_NameOfColor(colorPtr), 0); - if (cmdString != NULL) { - Tcl_AppendResult(interp, cmdString, "\n", (char *) NULL); - return TCL_OK; - } - } - - /* - * No color map entry for this color. Grab the color's intensities - * and output Postscript commands for them. Special note: X uses - * a range of 0-65535 for intensities, but most displays only use - * a range of 0-255, which maps to (0, 256, 512, ... 65280) in the - * X scale. This means that there's no way to get perfect white, - * since the highest intensity is only 65280 out of 65535. To - * work around this problem, rescale the X intensity to a 0-255 - * scale and use that as the basis for the Postscript colors. This - * scheme still won't work if the display only uses 4 bits per color, - * but most diplays use at least 8 bits. - */ - - tmp = colorPtr->red; - red = ((double) (tmp >> 8))/255.0; - tmp = colorPtr->green; - green = ((double) (tmp >> 8))/255.0; - tmp = colorPtr->blue; - blue = ((double) (tmp >> 8))/255.0; - sprintf(string, "%.3f %.3f %.3f setrgbcolor AdjustColor\n", - red, green, blue); - Tcl_AppendResult(interp, string, (char *) NULL); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsFont -- - * - * This procedure is called by individual canvas items when - * they want to output text. Given information about an X - * font, this procedure will generate Postscript commands - * to set up an appropriate font in Postscript. - * - * Results: - * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. - * If no error occurs, then additional Postscript will be - * appended to the interp->result. - * - * Side effects: - * The Postscript font name is entered into psInfoPtr->fontTable - * if it wasn't already there. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasPsFont(interp, canvas, tkfont) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ - Tk_Font tkfont; /* Information about font in which text - * is to be printed. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; - char *end; - char pointString[20]; - Tcl_DString ds; - int i, points; - - /* - * First, look up the font's name in the font map, if there is one. - * If there is an entry for this font, it consists of a list - * containing font name and size. Use this information. - */ - - Tcl_DStringInit(&ds); - - if (psInfoPtr->fontVar != NULL) { - char *list, **argv; - int argc; - double size; - char *name; - - name = Tk_NameOfFont(tkfont); - list = Tcl_GetVar2(interp, psInfoPtr->fontVar, name, 0); - if (list != NULL) { - if (Tcl_SplitList(interp, list, &argc, &argv) != TCL_OK) { - badMapEntry: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad font map entry for \"", name, - "\": \"", list, "\"", (char *) NULL); - return TCL_ERROR; - } - if (argc != 2) { - goto badMapEntry; - } - size = strtod(argv[1], &end); - if ((size <= 0) || (*end != 0)) { - goto badMapEntry; - } - - Tcl_DStringAppend(&ds, argv[0], -1); - points = (int) size; - - ckfree((char *) argv); - goto findfont; - } - } - - points = Tk_PostscriptFontName(tkfont, &ds); - - findfont: - sprintf(pointString, "%d", points); - Tcl_AppendResult(interp, "/", Tcl_DStringValue(&ds), " findfont ", - pointString, " scalefont ", (char *) NULL); - if (strncasecmp(Tcl_DStringValue(&ds), "Symbol", 7) != 0) { - Tcl_AppendResult(interp, "ISOEncode ", (char *) NULL); - } - Tcl_AppendResult(interp, "setfont\n", (char *) NULL); - Tcl_CreateHashEntry(&psInfoPtr->fontTable, Tcl_DStringValue(&ds), &i); - Tcl_DStringFree(&ds); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsBitmap -- - * - * This procedure is called to output the contents of a - * sub-region of a bitmap in proper image data format for - * Postscript (i.e. data between angle brackets, one bit - * per pixel). - * - * Results: - * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. - * If no error occurs, then additional Postscript will be - * appended to interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ - Pixmap bitmap; /* Bitmap for which to generate - * Postscript. */ - int startX, startY; /* Coordinates of upper-left corner - * of rectangular region to output. */ - int width, height; /* Height of rectangular region. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; - XImage *imagePtr; - int charsInLine, x, y, lastX, lastY, value, mask; - unsigned int totalWidth, totalHeight; - char string[100]; - Window dummyRoot; - int dummyX, dummyY; - unsigned dummyBorderwidth, dummyDepth; - - if (psInfoPtr->prepass) { - return TCL_OK; - } - - /* - * The following call should probably be a call to Tk_SizeOfBitmap - * instead, but it seems that we are occasionally invoked by custom - * item types that create their own bitmaps without registering them - * with Tk. XGetGeometry is a bit slower than Tk_SizeOfBitmap, but - * it shouldn't matter here. - */ - - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, - (int *) &dummyX, (int *) &dummyY, (unsigned int *) &totalWidth, - (unsigned int *) &totalHeight, &dummyBorderwidth, &dummyDepth); - imagePtr = XGetImage(Tk_Display(canvasPtr->tkwin), bitmap, 0, 0, - totalWidth, totalHeight, 1, XYPixmap); - Tcl_AppendResult(interp, "<", (char *) NULL); - mask = 0x80; - value = 0; - charsInLine = 0; - lastX = startX + width - 1; - lastY = startY + height - 1; - for (y = lastY; y >= startY; y--) { - for (x = startX; x <= lastX; x++) { - if (XGetPixel(imagePtr, x, y)) { - value |= mask; - } - mask >>= 1; - if (mask == 0) { - sprintf(string, "%02x", value); - Tcl_AppendResult(interp, string, (char *) NULL); - mask = 0x80; - value = 0; - charsInLine += 2; - if (charsInLine >= 60) { - Tcl_AppendResult(interp, "\n", (char *) NULL); - charsInLine = 0; - } - } - } - if (mask != 0x80) { - sprintf(string, "%02x", value); - Tcl_AppendResult(interp, string, (char *) NULL); - mask = 0x80; - value = 0; - charsInLine += 2; - } - } - Tcl_AppendResult(interp, ">", (char *) NULL); - XDestroyImage(imagePtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsStipple -- - * - * This procedure is called by individual canvas items when - * they have created a path that they'd like to be filled with - * a stipple pattern. Given information about an X bitmap, - * this procedure will generate Postscript commands to fill - * the current clip region using a stipple pattern defined by the - * bitmap. - * - * Results: - * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. - * If no error occurs, then additional Postscript will be - * appended to interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasPsStipple(interp, canvas, bitmap) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ - Pixmap bitmap; /* Bitmap to use for stippling. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; - int width, height; - char string[100]; - Window dummyRoot; - int dummyX, dummyY; - unsigned dummyBorderwidth, dummyDepth; - - if (psInfoPtr->prepass) { - return TCL_OK; - } - - /* - * The following call should probably be a call to Tk_SizeOfBitmap - * instead, but it seems that we are occasionally invoked by custom - * item types that create their own bitmaps without registering them - * with Tk. XGetGeometry is a bit slower than Tk_SizeOfBitmap, but - * it shouldn't matter here. - */ - - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, - (int *) &dummyX, (int *) &dummyY, (unsigned *) &width, - (unsigned *) &height, &dummyBorderwidth, &dummyDepth); - sprintf(string, "%d %d ", width, height); - Tcl_AppendResult(interp, string, (char *) NULL); - if (Tk_CanvasPsBitmap(interp, (Tk_Canvas) canvasPtr, bitmap, 0, 0, - width, height) != TCL_OK) { - return TCL_ERROR; - } - Tcl_AppendResult(interp, " StippleFill\n", (char *) NULL); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsY -- - * - * Given a y-coordinate in canvas coordinates, this procedure - * returns a y-coordinate to use for Postscript output. - * - * Results: - * Returns the Postscript coordinate that corresponds to - * "y". - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -double -Tk_CanvasPsY(canvas, y) - Tk_Canvas canvas; /* Token for canvas on whose behalf - * Postscript is being generated. */ - double y; /* Y-coordinate in canvas coords. */ -{ - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; - - return psInfoPtr->y2 - y; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasPsPath -- - * - * Given an array of points for a path, generate Postscript - * commands to create the path. - * - * Results: - * Postscript commands get appended to what's in interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) - Tcl_Interp *interp; /* Put generated Postscript in this - * interpreter's result field. */ - Tk_Canvas canvas; /* Canvas on whose behalf Postscript - * is being generated. */ - double *coordPtr; /* Pointer to first in array of - * 2*numPoints coordinates giving - * points for path. */ - int numPoints; /* Number of points at *coordPtr. */ -{ - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; - char buffer[200]; - - if (psInfoPtr->prepass) { - return; - } - sprintf(buffer, "%.15g %.15g moveto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); - Tcl_AppendResult(interp, buffer, (char *) NULL); - for (numPoints--, coordPtr += 2; numPoints > 0; - numPoints--, coordPtr += 2) { - sprintf(buffer, "%.15g %.15g lineto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } -} - -/* - *-------------------------------------------------------------- - * - * GetPostscriptPoints -- - * - * Given a string, returns the number of Postscript points - * corresponding to that string. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * screen distance is stored at *doublePtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -GetPostscriptPoints(interp, string, doublePtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - char *string; /* String describing a screen distance. */ - double *doublePtr; /* Place to store converted result. */ -{ - char *end; - double d; - - d = strtod(string, &end); - if (end == string) { - error: - Tcl_AppendResult(interp, "bad distance \"", string, - "\"", (char *) NULL); - return TCL_ERROR; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - switch (*end) { - case 'c': - d *= 72.0/2.54; - end++; - break; - case 'i': - d *= 72.0; - end++; - break; - case 'm': - d *= 72.0/25.4; - end++; - break; - case 0: - break; - case 'p': - end++; - break; - default: - goto error; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - if (*end != 0) { - goto error; - } - *doublePtr = d; - return TCL_OK; -} diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c deleted file mode 100644 index 298553a..0000000 --- a/generic/tkCanvText.c +++ /dev/null @@ -1,1313 +0,0 @@ -/* - * tkCanvText.c -- - * - * This file implements text items for canvas widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvText.c,v 1.2 1998/09/14 18:23:05 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkCanvas.h" -#include "tkPort.h" -#include "default.h" - -/* - * The structure below defines the record for each text item. - */ - -typedef struct TextItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - Tk_CanvasTextInfo *textInfoPtr; - /* Pointer to a structure containing - * information about the selection and - * insertion cursor. The structure is owned - * by (and shared with) the generic canvas - * code. */ - /* - * Fields that are set by widget commands other than "configure". - */ - - double x, y; /* Positioning point for text. */ - int insertPos; /* Insertion cursor is displayed just to left - * of character with this index. */ - - /* - * Configuration settings that are updated by Tk_ConfigureWidget. - */ - - Tk_Anchor anchor; /* Where to anchor text relative to (x,y). */ - XColor *color; /* Color for text. */ - Tk_Font tkfont; /* Font for drawing text. */ - Tk_Justify justify; /* Justification mode for text. */ - Pixmap stipple; /* Stipple bitmap for text, or None. */ - char *text; /* Text for item (malloc-ed). */ - int width; /* Width of lines for word-wrap, pixels. - * Zero means no word-wrap. */ - - /* - * Fields whose values are derived from the current values of the - * configuration settings above. - */ - - int numChars; /* Number of non-NULL characters in text. */ - Tk_TextLayout textLayout; /* Cached text layout information. */ - int leftEdge; /* Pixel location of the left edge of the - * text item; where the left border of the - * text layout is drawn. */ - int rightEdge; /* Pixel just to right of right edge of - * area of text item. Used for selecting up - * to end of line. */ - GC gc; /* Graphics context for drawing text. */ - GC selTextGC; /* Graphics context for selected text. */ - GC cursorOffGC; /* If not None, this gives a graphics context - * to use to draw the insertion cursor when - * it's off. Used if the selection and - * insertion cursor colors are the same. */ -} TextItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, - "center", Tk_Offset(TextItem, anchor), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - "black", Tk_Offset(TextItem, color), 0}, - {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, - DEF_CANVTEXT_FONT, Tk_Offset(TextItem, tkfont), 0}, - {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, - "left", Tk_Offset(TextItem, justify), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_STRING, "-text", (char *) NULL, (char *) NULL, - "", Tk_Offset(TextItem, text), 0}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TextItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ComputeTextBbox _ANSI_ARGS_((Tk_Canvas canvas, - TextItem *textPtr)); -static int ConfigureText _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateText _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteText _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayCanvText _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static int GetSelText _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int offset, char *buffer, - int maxBytes)); -static int GetTextIndex _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, - char *indexString, int *indexPtr)); -static void ScaleText _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void SetTextCursor _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int index)); -static int TextCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); -static void TextDeleteChars _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int first, int last)); -static void TextInsert _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, int beforeThis, char *string)); -static int TextToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double TextToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); -static int TextToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static void TranslateText _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * The structures below defines the rectangle and oval item types - * by means of procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkTextType = { - "text", /* name */ - sizeof(TextItem), /* itemSize */ - CreateText, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureText, /* configureProc */ - TextCoords, /* coordProc */ - DeleteText, /* deleteProc */ - DisplayCanvText, /* displayProc */ - 0, /* alwaysRedraw */ - TextToPoint, /* pointProc */ - TextToArea, /* areaProc */ - TextToPostscript, /* postscriptProc */ - ScaleText, /* scaleProc */ - TranslateText, /* translateProc */ - GetTextIndex, /* indexProc */ - SetTextCursor, /* icursorProc */ - GetSelText, /* selectionProc */ - TextInsert, /* insertProc */ - TextDeleteChars, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - *-------------------------------------------------------------- - * - * CreateText -- - * - * This procedure is invoked to create a new text item - * in a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item then an error message is left in - * interp->result; in this case itemPtr is left uninitialized - * so it can be safely freed by the caller. - * - * Side effects: - * A new text item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateText(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Carry out initialization that is needed in order to clean - * up after errors during the the remainder of this procedure. - */ - - textPtr->textInfoPtr = Tk_CanvasGetTextInfo(canvas); - - textPtr->insertPos = 0; - - textPtr->anchor = TK_ANCHOR_CENTER; - textPtr->color = NULL; - textPtr->tkfont = NULL; - textPtr->justify = TK_JUSTIFY_LEFT; - textPtr->stipple = None; - textPtr->text = NULL; - textPtr->width = 0; - - textPtr->numChars = 0; - textPtr->textLayout = NULL; - textPtr->leftEdge = 0; - textPtr->rightEdge = 0; - textPtr->gc = None; - textPtr->selTextGC = None; - textPtr->cursorOffGC = None; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &textPtr->y) - != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureText(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TextCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on text items. See the user documentation for - * details on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -TextCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, textPtr->x, x); - Tcl_PrintDouble(interp, textPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &textPtr->y) != TCL_OK)) { - return TCL_ERROR; - } - ComputeTextBbox(canvas, textPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureText -- - * - * This procedure is invoked to configure various aspects - * of a text item, such as its border and background colors. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information, such as colors and stipple - * patterns, may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureText(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - XGCValues gcValues; - GC newGC, newSelGC; - unsigned long mask; - Tk_Window tkwin; - Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - XColor *selBgColorPtr; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) textPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as - * graphics contexts. - */ - - newGC = newSelGC = None; - if ((textPtr->color != NULL) && (textPtr->tkfont != NULL)) { - gcValues.foreground = textPtr->color->pixel; - gcValues.font = Tk_FontId(textPtr->tkfont); - mask = GCForeground|GCFont; - if (textPtr->stipple != None) { - gcValues.stipple = textPtr->stipple; - gcValues.fill_style = FillStippled; - mask |= GCForeground|GCStipple|GCFillStyle; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - gcValues.foreground = textInfoPtr->selFgColorPtr->pixel; - newSelGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (textPtr->gc != None) { - Tk_FreeGC(Tk_Display(tkwin), textPtr->gc); - } - textPtr->gc = newGC; - if (textPtr->selTextGC != None) { - Tk_FreeGC(Tk_Display(tkwin), textPtr->selTextGC); - } - textPtr->selTextGC = newSelGC; - - selBgColorPtr = Tk_3DBorderColor(textInfoPtr->selBorder); - if (Tk_3DBorderColor(textInfoPtr->insertBorder)->pixel - == selBgColorPtr->pixel) { - if (selBgColorPtr->pixel == BlackPixelOfScreen(Tk_Screen(tkwin))) { - gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); - } else { - gcValues.foreground = BlackPixelOfScreen(Tk_Screen(tkwin)); - } - newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); - } else { - newGC = None; - } - if (textPtr->cursorOffGC != None) { - Tk_FreeGC(Tk_Display(tkwin), textPtr->cursorOffGC); - } - textPtr->cursorOffGC = newGC; - - - /* - * If the text was changed, move the selection and insertion indices - * to keep them inside the item. - */ - - textPtr->numChars = strlen(textPtr->text); - if (textInfoPtr->selItemPtr == itemPtr) { - if (textInfoPtr->selectFirst >= textPtr->numChars) { - textInfoPtr->selItemPtr = NULL; - } else { - if (textInfoPtr->selectLast >= textPtr->numChars) { - textInfoPtr->selectLast = textPtr->numChars-1; - } - if ((textInfoPtr->anchorItemPtr == itemPtr) - && (textInfoPtr->selectAnchor >= textPtr->numChars)) { - textInfoPtr->selectAnchor = textPtr->numChars-1; - } - } - } - if (textPtr->insertPos >= textPtr->numChars) { - textPtr->insertPos = textPtr->numChars; - } - - ComputeTextBbox(canvas, textPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteText -- - * - * This procedure is called to clean up the data structure - * associated with a text item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteText(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - - if (textPtr->color != NULL) { - Tk_FreeColor(textPtr->color); - } - Tk_FreeFont(textPtr->tkfont); - if (textPtr->stipple != None) { - Tk_FreeBitmap(display, textPtr->stipple); - } - if (textPtr->text != NULL) { - ckfree(textPtr->text); - } - - Tk_FreeTextLayout(textPtr->textLayout); - if (textPtr->gc != None) { - Tk_FreeGC(display, textPtr->gc); - } - if (textPtr->selTextGC != None) { - Tk_FreeGC(display, textPtr->selTextGC); - } - if (textPtr->cursorOffGC != None) { - Tk_FreeGC(display, textPtr->cursorOffGC); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeTextBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a text item. - * In addition, it recomputes all of the geometry information - * used to display a text item or check for mouse hits. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr, and the linePtr structure is regenerated - * for itemPtr. - * - *-------------------------------------------------------------- - */ - -static void -ComputeTextBbox(canvas, textPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - TextItem *textPtr; /* Item whose bbos is to be - * recomputed. */ -{ - Tk_CanvasTextInfo *textInfoPtr; - int leftX, topY, width, height, fudge; - - Tk_FreeTextLayout(textPtr->textLayout); - textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont, - textPtr->text, textPtr->numChars, textPtr->width, - textPtr->justify, 0, &width, &height); - - /* - * Use overall geometry information to compute the top-left corner - * of the bounding box for the text item. - */ - - leftX = (int) (textPtr->x + 0.5); - topY = (int) (textPtr->y + 0.5); - switch (textPtr->anchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_N: - case TK_ANCHOR_NE: - break; - - case TK_ANCHOR_W: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_E: - topY -= height / 2; - break; - - case TK_ANCHOR_SW: - case TK_ANCHOR_S: - case TK_ANCHOR_SE: - topY -= height; - break; - } - switch (textPtr->anchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_W: - case TK_ANCHOR_SW: - break; - - case TK_ANCHOR_N: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_S: - leftX -= width / 2; - break; - - case TK_ANCHOR_NE: - case TK_ANCHOR_E: - case TK_ANCHOR_SE: - leftX -= width; - break; - } - - textPtr->leftEdge = leftX; - textPtr->rightEdge = leftX + width; - - /* - * Last of all, update the bounding box for the item. The item's - * bounding box includes the bounding box of all its lines, plus - * an extra fudge factor for the cursor border (which could - * potentially be quite large). - */ - - textInfoPtr = textPtr->textInfoPtr; - fudge = (textInfoPtr->insertWidth + 1) / 2; - if (textInfoPtr->selBorderWidth > fudge) { - fudge = textInfoPtr->selBorderWidth; - } - textPtr->header.x1 = leftX - fudge; - textPtr->header.y1 = topY; - textPtr->header.x2 = leftX + width + fudge; - textPtr->header.y2 = topY + height; -} - -/* - *-------------------------------------------------------------- - * - * DisplayCanvText -- - * - * This procedure is invoked to draw a text item in a given - * drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - TextItem *textPtr; - Tk_CanvasTextInfo *textInfoPtr; - int selFirst, selLast; - short drawableX, drawableY; - - textPtr = (TextItem *) itemPtr; - textInfoPtr = textPtr->textInfoPtr; - - if (textPtr->gc == None) { - return; - } - - /* - * If we're stippling, then modify the stipple offset in the GC. Be - * sure to reset the offset when done, since the GC is supposed to be - * read-only. - */ - - if (textPtr->stipple != None) { - Tk_CanvasSetStippleOrigin(canvas, textPtr->gc); - } - - selFirst = -1; - selLast = 0; /* lint. */ - if (textInfoPtr->selItemPtr == itemPtr) { - selFirst = textInfoPtr->selectFirst; - selLast = textInfoPtr->selectLast; - if (selLast >= textPtr->numChars) { - selLast = textPtr->numChars - 1; - } - if ((selFirst >= 0) && (selFirst <= selLast)) { - /* - * Draw a special background under the selection. - */ - - int xFirst, yFirst, hFirst; - int xLast, yLast, wLast; - - Tk_CharBbox(textPtr->textLayout, selFirst, - &xFirst, &yFirst, NULL, &hFirst); - Tk_CharBbox(textPtr->textLayout, selLast, - &xLast, &yLast, &wLast, NULL); - - /* - * If the selection spans the end of this line, then display - * selection background all the way to the end of the line. - * However, for the last line we only want to display up to the - * last character, not the end of the line. - */ - - x = xFirst; - height = hFirst; - for (y = yFirst ; y <= yLast; y += height) { - if (y == yLast) { - width = (xLast + wLast) - x; - } else { - width = textPtr->rightEdge - textPtr->leftEdge - x; - } - Tk_CanvasDrawableCoords(canvas, - (double) (textPtr->leftEdge + x - - textInfoPtr->selBorderWidth), - (double) (textPtr->header.y1 + y), - &drawableX, &drawableY); - Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable, - textInfoPtr->selBorder, drawableX, drawableY, - width + 2 * textInfoPtr->selBorderWidth, - height, textInfoPtr->selBorderWidth, TK_RELIEF_RAISED); - x = 0; - } - } - } - - /* - * If the insertion point should be displayed, then draw a special - * background for the cursor before drawing the text. Note: if - * we're the cursor item but the cursor is turned off, then redraw - * background over the area of the cursor. This guarantees that - * the selection won't make the cursor invisible on mono displays, - * where both are drawn in the same color. - */ - - if ((textInfoPtr->focusItemPtr == itemPtr) && (textInfoPtr->gotFocus)) { - if (Tk_CharBbox(textPtr->textLayout, textPtr->insertPos, - &x, &y, NULL, &height)) { - Tk_CanvasDrawableCoords(canvas, - (double) (textPtr->leftEdge + x - - (textInfoPtr->insertWidth / 2)), - (double) (textPtr->header.y1 + y), - &drawableX, &drawableY); - if (textInfoPtr->cursorOn) { - Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable, - textInfoPtr->insertBorder, - drawableX, drawableY, - textInfoPtr->insertWidth, height, - textInfoPtr->insertBorderWidth, TK_RELIEF_RAISED); - } else if (textPtr->cursorOffGC != None) { - /* - * Redraw the background over the area of the cursor, - * even though the cursor is turned off. This - * guarantees that the selection won't make the cursor - * invisible on mono displays, where both may be drawn - * in the same color. - */ - - XFillRectangle(display, drawable, textPtr->cursorOffGC, - drawableX, drawableY, - (unsigned) textInfoPtr->insertWidth, - (unsigned) height); - } - } - } - - - /* - * Display the text in two pieces: draw the entire text item, then - * draw the selected text on top of it. The selected text then - * will only need to be drawn if it has different attributes (such - * as foreground color) than regular text. - */ - - Tk_CanvasDrawableCoords(canvas, (double) textPtr->leftEdge, - (double) textPtr->header.y1, &drawableX, &drawableY); - Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, - drawableX, drawableY, 0, -1); - - if ((selFirst >= 0) && (textPtr->selTextGC != textPtr->gc)) { - Tk_DrawTextLayout(display, drawable, textPtr->selTextGC, - textPtr->textLayout, drawableX, drawableY, selFirst, - selLast + 1); - } - - if (textPtr->stipple != None) { - XSetTSOrigin(display, textPtr->gc, 0, 0); - } -} - -/* - *-------------------------------------------------------------- - * - * TextInsert -- - * - * Insert characters into a text item at a given position. - * - * Results: - * None. - * - * Side effects: - * The text in the given item is modified. The cursor and - * selection positions are also modified to reflect the - * insertion. - * - *-------------------------------------------------------------- - */ - -static void -TextInsert(canvas, itemPtr, beforeThis, string) - Tk_Canvas canvas; /* Canvas containing text item. */ - Tk_Item *itemPtr; /* Text item to be modified. */ - int beforeThis; /* Index of character before which text is - * to be inserted. */ - char *string; /* New characters to be inserted. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - int length; - char *new; - Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - - length = strlen(string); - if (length == 0) { - return; - } - if (beforeThis < 0) { - beforeThis = 0; - } - if (beforeThis > textPtr->numChars) { - beforeThis = textPtr->numChars; - } - - new = (char *) ckalloc((unsigned) (textPtr->numChars + length + 1)); - strncpy(new, textPtr->text, (size_t) beforeThis); - strcpy(new+beforeThis, string); - strcpy(new+beforeThis+length, textPtr->text+beforeThis); - ckfree(textPtr->text); - textPtr->text = new; - textPtr->numChars += length; - - /* - * Inserting characters invalidates indices such as those for the - * selection and cursor. Update the indices appropriately. - */ - - if (textInfoPtr->selItemPtr == itemPtr) { - if (textInfoPtr->selectFirst >= beforeThis) { - textInfoPtr->selectFirst += length; - } - if (textInfoPtr->selectLast >= beforeThis) { - textInfoPtr->selectLast += length; - } - if ((textInfoPtr->anchorItemPtr == itemPtr) - && (textInfoPtr->selectAnchor >= beforeThis)) { - textInfoPtr->selectAnchor += length; - } - } - if (textPtr->insertPos >= beforeThis) { - textPtr->insertPos += length; - } - ComputeTextBbox(canvas, textPtr); -} - -/* - *-------------------------------------------------------------- - * - * TextDeleteChars -- - * - * Delete one or more characters from a text item. - * - * Results: - * None. - * - * Side effects: - * Characters between "first" and "last", inclusive, get - * deleted from itemPtr, and things like the selection - * position get updated. - * - *-------------------------------------------------------------- - */ - -static void -TextDeleteChars(canvas, itemPtr, first, last) - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Item in which to delete characters. */ - int first; /* Index of first character to delete. */ - int last; /* Index of last character to delete. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - int count; - char *new; - Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - - if (first < 0) { - first = 0; - } - if (last >= textPtr->numChars) { - last = textPtr->numChars-1; - } - if (first > last) { - return; - } - count = last + 1 - first; - - new = (char *) ckalloc((unsigned) (textPtr->numChars + 1 - count)); - strncpy(new, textPtr->text, (size_t) first); - strcpy(new+first, textPtr->text+last+1); - ckfree(textPtr->text); - textPtr->text = new; - textPtr->numChars -= count; - - /* - * Update indexes for the selection and cursor to reflect the - * renumbering of the remaining characters. - */ - - if (textInfoPtr->selItemPtr == itemPtr) { - if (textInfoPtr->selectFirst > first) { - textInfoPtr->selectFirst -= count; - if (textInfoPtr->selectFirst < first) { - textInfoPtr->selectFirst = first; - } - } - if (textInfoPtr->selectLast >= first) { - textInfoPtr->selectLast -= count; - if (textInfoPtr->selectLast < (first-1)) { - textInfoPtr->selectLast = (first-1); - } - } - if (textInfoPtr->selectFirst > textInfoPtr->selectLast) { - textInfoPtr->selItemPtr = NULL; - } - if ((textInfoPtr->anchorItemPtr == itemPtr) - && (textInfoPtr->selectAnchor > first)) { - textInfoPtr->selectAnchor -= count; - if (textInfoPtr->selectAnchor < first) { - textInfoPtr->selectAnchor = first; - } - } - } - if (textPtr->insertPos > first) { - textPtr->insertPos -= count; - if (textPtr->insertPos < first) { - textPtr->insertPos = first; - } - } - ComputeTextBbox(canvas, textPtr); - return; -} - -/* - *-------------------------------------------------------------- - * - * TextToPoint -- - * - * Computes the distance from a given point to a given - * text item, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are pointPtr[0] and pointPtr[1] is inside the text item. If - * the point isn't inside the text item then the return value - * is the distance from the point to the text item. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static double -TextToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - TextItem *textPtr; - - textPtr = (TextItem *) itemPtr; - return (double) Tk_DistanceToTextLayout(textPtr->textLayout, - (int) pointPtr[0] - textPtr->leftEdge, - (int) pointPtr[1] - textPtr->header.y1); -} - -/* - *-------------------------------------------------------------- - * - * TextToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangle. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -TextToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Item to check against rectangle. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - TextItem *textPtr; - - textPtr = (TextItem *) itemPtr; - return Tk_IntersectTextLayout(textPtr->textLayout, - (int) (rectPtr[0] + 0.5) - textPtr->leftEdge, - (int) (rectPtr[1] + 0.5) - textPtr->header.y1, - (int) (rectPtr[2] - rectPtr[0] + 0.5), - (int) (rectPtr[3] - rectPtr[1] + 0.5)); -} - -/* - *-------------------------------------------------------------- - * - * ScaleText -- - * - * This procedure is invoked to rescale a text item. - * - * Results: - * None. - * - * Side effects: - * Scales the position of the text, but not the size - * of the font for the text. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ScaleText(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - - textPtr->x = originX + scaleX*(textPtr->x - originX); - textPtr->y = originY + scaleY*(textPtr->y - originY); - ComputeTextBbox(canvas, textPtr); - return; -} - -/* - *-------------------------------------------------------------- - * - * TranslateText -- - * - * This procedure is called to move a text item by a - * given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the text item is offset by (xDelta, yDelta), - * and the bounding box is updated in the generic part of the - * item structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateText(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - - textPtr->x += deltaX; - textPtr->y += deltaY; - ComputeTextBbox(canvas, textPtr); -} - -/* - *-------------------------------------------------------------- - * - * GetTextIndex -- - * - * Parse an index into a text item and return either its value - * or an error. - * - * Results: - * A standard Tcl result. If all went well, then *indexPtr is - * filled in with the index (into itemPtr) corresponding to - * string. Otherwise an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -GetTextIndex(interp, canvas, itemPtr, string, indexPtr) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item for which the index is being - * specified. */ - char *string; /* Specification of a particular character - * in itemPtr's text. */ - int *indexPtr; /* Where to store converted index. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - size_t length; - int c; - TkCanvas *canvasPtr = (TkCanvas *) canvas; - Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - - c = string[0]; - length = strlen(string); - - if ((c == 'e') && (strncmp(string, "end", length) == 0)) { - *indexPtr = textPtr->numChars; - } else if ((c == 'i') && (strncmp(string, "insert", length) == 0)) { - *indexPtr = textPtr->insertPos; - } else if ((c == 's') && (strncmp(string, "sel.first", length) == 0) - && (length >= 5)) { - if (textInfoPtr->selItemPtr != itemPtr) { - interp->result = "selection isn't in item"; - return TCL_ERROR; - } - *indexPtr = textInfoPtr->selectFirst; - } else if ((c == 's') && (strncmp(string, "sel.last", length) == 0) - && (length >= 5)) { - if (textInfoPtr->selItemPtr != itemPtr) { - interp->result = "selection isn't in item"; - return TCL_ERROR; - } - *indexPtr = textInfoPtr->selectLast; - } else if (c == '@') { - int x, y; - double tmp; - char *end, *p; - - p = string+1; - tmp = strtod(p, &end); - if ((end == p) || (*end != ',')) { - goto badIndex; - } - x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5); - p = end+1; - tmp = strtod(p, &end); - if ((end == p) || (*end != 0)) { - goto badIndex; - } - y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5); - *indexPtr = Tk_PointToChar(textPtr->textLayout, - x + canvasPtr->scrollX1 - textPtr->leftEdge, - y + canvasPtr->scrollY1 - textPtr->header.y1); - } else if (Tcl_GetInt(interp, string, indexPtr) == TCL_OK) { - if (*indexPtr < 0){ - *indexPtr = 0; - } else if (*indexPtr > textPtr->numChars) { - *indexPtr = textPtr->numChars; - } - } else { - /* - * Some of the paths here leave messages in interp->result, - * so we have to clear it out before storing our own message. - */ - - badIndex: - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - Tcl_AppendResult(interp, "bad index \"", string, "\"", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * SetTextCursor -- - * - * Set the position of the insertion cursor in this item. - * - * Results: - * None. - * - * Side effects: - * The cursor position will change. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -SetTextCursor(canvas, itemPtr, index) - Tk_Canvas canvas; /* Record describing canvas widget. */ - Tk_Item *itemPtr; /* Text item in which cursor position - * is to be set. */ - int index; /* Index of character just before which - * cursor is to be positioned. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - - if (index < 0) { - textPtr->insertPos = 0; - } else if (index > textPtr->numChars) { - textPtr->insertPos = textPtr->numChars; - } else { - textPtr->insertPos = index; - } -} - -/* - *-------------------------------------------------------------- - * - * GetSelText -- - * - * This procedure is invoked to return the selected portion - * of a text item. It is only called when this item has - * the selection. - * - * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -GetSelText(canvas, itemPtr, offset, buffer, maxBytes) - Tk_Canvas canvas; /* Canvas containing selection. */ - Tk_Item *itemPtr; /* Text item containing selection. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - int count; - Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - - count = textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst - offset; - if (textInfoPtr->selectLast == textPtr->numChars) { - count -= 1; - } - if (count > maxBytes) { - count = maxBytes; - } - if (count <= 0) { - return 0; - } - strncpy(buffer, textPtr->text + textInfoPtr->selectFirst + offset, - (size_t) count); - buffer[count] = '\0'; - return count; -} - -/* - *-------------------------------------------------------------- - * - * TextToPostscript -- - * - * This procedure is called to generate Postscript for - * text items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used - * to be there. If no error occurs, then Postscript for the - * item is appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -TextToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - TextItem *textPtr = (TextItem *) itemPtr; - int x, y; - Tk_FontMetrics fm; - char *justify; - char buffer[500]; - - if (textPtr->color == NULL) { - return TCL_OK; - } - - if (Tk_CanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) { - return TCL_ERROR; - } - if (prepass != 0) { - return TCL_OK; - } - if (Tk_CanvasPsColor(interp, canvas, textPtr->color) != TCL_OK) { - return TCL_ERROR; - } - if (textPtr->stipple != None) { - Tcl_AppendResult(interp, "/StippleText {\n ", - (char *) NULL); - Tk_CanvasPsStipple(interp, canvas, textPtr->stipple); - Tcl_AppendResult(interp, "} bind def\n", (char *) NULL); - } - - sprintf(buffer, "%.15g %.15g [\n", textPtr->x, - Tk_CanvasPsY(canvas, textPtr->y)); - Tcl_AppendResult(interp, buffer, (char *) NULL); - - Tk_TextLayoutToPostscript(interp, textPtr->textLayout); - - x = 0; y = 0; justify = NULL; /* lint. */ - switch (textPtr->anchor) { - case TK_ANCHOR_NW: x = 0; y = 0; break; - case TK_ANCHOR_N: x = 1; y = 0; break; - case TK_ANCHOR_NE: x = 2; y = 0; break; - case TK_ANCHOR_E: x = 2; y = 1; break; - case TK_ANCHOR_SE: x = 2; y = 2; break; - case TK_ANCHOR_S: x = 1; y = 2; break; - case TK_ANCHOR_SW: x = 0; y = 2; break; - case TK_ANCHOR_W: x = 0; y = 1; break; - case TK_ANCHOR_CENTER: x = 1; y = 1; break; - } - switch (textPtr->justify) { - case TK_JUSTIFY_LEFT: justify = "0"; break; - case TK_JUSTIFY_CENTER: justify = "0.5";break; - case TK_JUSTIFY_RIGHT: justify = "1"; break; - } - - Tk_GetFontMetrics(textPtr->tkfont, &fm); - sprintf(buffer, "] %d %g %g %s %s DrawText\n", - fm.linespace, x / -2.0, y / 2.0, justify, - ((textPtr->stipple == None) ? "false" : "true")); - Tcl_AppendResult(interp, buffer, (char *) NULL); - - return TCL_OK; -} diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c deleted file mode 100644 index 16a5ffa..0000000 --- a/generic/tkCanvUtil.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * tkCanvUtil.c -- - * - * This procedure contains a collection of utility procedures - * used by the implementations of various canvas item types. - * - * Copyright (c) 1994 Sun Microsystems, Inc. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvUtil.c,v 1.2 1998/09/14 18:23:06 stanton Exp $ - */ - -#include "tk.h" -#include "tkCanvas.h" -#include "tkPort.h" - - -/* - *---------------------------------------------------------------------- - * - * Tk_CanvasTkwin -- - * - * Given a token for a canvas, this procedure returns the - * widget that represents the canvas. - * - * Results: - * The return value is a handle for the widget. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -Tk_CanvasTkwin(canvas) - Tk_Canvas canvas; /* Token for the canvas. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - return canvasPtr->tkwin; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CanvasDrawableCoords -- - * - * Given an (x,y) coordinate pair within a canvas, this procedure - * returns the corresponding coordinates at which the point should - * be drawn in the drawable used for display. - * - * Results: - * There is no return value. The values at *drawableXPtr and - * *drawableYPtr are filled in with the coordinates at which - * x and y should be drawn. These coordinates are clipped - * to fit within a "short", since this is what X uses in - * most cases for drawing. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CanvasDrawableCoords(canvas, x, y, drawableXPtr, drawableYPtr) - Tk_Canvas canvas; /* Token for the canvas. */ - double x, y; /* Coordinates in canvas space. */ - short *drawableXPtr, *drawableYPtr; /* Screen coordinates are stored - * here. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - double tmp; - - tmp = x - canvasPtr->drawableXOrigin; - if (tmp > 0) { - tmp += 0.5; - } else { - tmp -= 0.5; - } - if (tmp > 32767) { - *drawableXPtr = 32767; - } else if (tmp < -32768) { - *drawableXPtr = -32768; - } else { - *drawableXPtr = (short) tmp; - } - - tmp = y - canvasPtr->drawableYOrigin; - if (tmp > 0) { - tmp += 0.5; - } else { - tmp -= 0.5; - } - if (tmp > 32767) { - *drawableYPtr = 32767; - } else if (tmp < -32768) { - *drawableYPtr = -32768; - } else { - *drawableYPtr = (short) tmp; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CanvasWindowCoords -- - * - * Given an (x,y) coordinate pair within a canvas, this procedure - * returns the corresponding coordinates in the canvas's window. - * - * Results: - * There is no return value. The values at *screenXPtr and - * *screenYPtr are filled in with the coordinates at which - * (x,y) appears in the canvas's window. These coordinates - * are clipped to fit within a "short", since this is what X - * uses in most cases for drawing. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CanvasWindowCoords(canvas, x, y, screenXPtr, screenYPtr) - Tk_Canvas canvas; /* Token for the canvas. */ - double x, y; /* Coordinates in canvas space. */ - short *screenXPtr, *screenYPtr; /* Screen coordinates are stored - * here. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - double tmp; - - tmp = x - canvasPtr->xOrigin; - if (tmp > 0) { - tmp += 0.5; - } else { - tmp -= 0.5; - } - if (tmp > 32767) { - *screenXPtr = 32767; - } else if (tmp < -32768) { - *screenXPtr = -32768; - } else { - *screenXPtr = (short) tmp; - } - - tmp = y - canvasPtr->yOrigin; - if (tmp > 0) { - tmp += 0.5; - } else { - tmp -= 0.5; - } - if (tmp > 32767) { - *screenYPtr = 32767; - } else if (tmp < -32768) { - *screenYPtr = -32768; - } else { - *screenYPtr = (short) tmp; - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasGetCoord -- - * - * Given a string, returns a floating-point canvas coordinate - * corresponding to that string. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * canvas coordinate is stored at *doublePtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasGetCoord(interp, canvas, string, doublePtr) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to which coordinate applies. */ - char *string; /* Describes coordinate (any screen - * coordinate form may be used here). */ - double *doublePtr; /* Place to store converted coordinate. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string, - doublePtr) != TCL_OK) { - return TCL_ERROR; - } - *doublePtr *= canvasPtr->pixelsPerMM; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CanvasSetStippleOrigin -- - * - * This procedure sets the stipple origin in a graphics context - * so that stipples drawn with the GC will line up with other - * stipples previously drawn in the canvas. - * - * Results: - * None. - * - * Side effects: - * The graphics context is modified. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CanvasSetStippleOrigin(canvas, gc) - Tk_Canvas canvas; /* Token for a canvas. */ - GC gc; /* Graphics context that is about to be - * used to draw a stippled pattern as - * part of redisplaying the canvas. */ - -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - - XSetTSOrigin(canvasPtr->display, gc, -canvasPtr->drawableXOrigin, - -canvasPtr->drawableYOrigin); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CanvasGetTextInfo -- - * - * This procedure returns a pointer to a structure containing - * information about the selection and insertion cursor for - * a canvas widget. Items such as text items save the pointer - * and use it to share access to the information with the generic - * canvas code. - * - * Results: - * The return value is a pointer to the structure holding text - * information for the canvas. Most of the fields should not - * be modified outside the generic canvas code; see the user - * documentation for details. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_CanvasTextInfo * -Tk_CanvasGetTextInfo(canvas) - Tk_Canvas canvas; /* Token for the canvas widget. */ -{ - return &((TkCanvas *) canvas)->textInfo; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasTagsParseProc -- - * - * This procedure is invoked during option processing to handle - * "-tags" options for canvas items. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * The tags for a given item get replaced by those indicated - * in the value argument. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasTagsParseProc(clientData, interp, tkwin, value, widgRec, offset) - ClientData clientData; /* Not used.*/ - Tcl_Interp *interp; /* Used for reporting errors. */ - Tk_Window tkwin; /* Window containing canvas widget. */ - char *value; /* Value of option (list of tag - * names). */ - char *widgRec; /* Pointer to record for item. */ - int offset; /* Offset into item (ignored). */ -{ - register Tk_Item *itemPtr = (Tk_Item *) widgRec; - int argc, i; - char **argv; - Tk_Uid *newPtr; - - /* - * Break the value up into the individual tag names. - */ - - if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Make sure that there's enough space in the item to hold the - * tag names. - */ - - if (itemPtr->tagSpace < argc) { - newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid))); - for (i = itemPtr->numTags-1; i >= 0; i--) { - newPtr[i] = itemPtr->tagPtr[i]; - } - if (itemPtr->tagPtr != itemPtr->staticTagSpace) { - ckfree((char *) itemPtr->tagPtr); - } - itemPtr->tagPtr = newPtr; - itemPtr->tagSpace = argc; - } - itemPtr->numTags = argc; - for (i = 0; i < argc; i++) { - itemPtr->tagPtr[i] = Tk_GetUid(argv[i]); - } - ckfree((char *) argv); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasTagsPrintProc -- - * - * This procedure is invoked by the Tk configuration code - * to produce a printable string for the "-tags" configuration - * option for canvas items. - * - * Results: - * The return value is a string describing all the tags for - * the item referred to by "widgRec". In addition, *freeProcPtr - * is filled in with the address of a procedure to call to free - * the result string when it's no longer needed (or NULL to - * indicate that the string doesn't need to be freed). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) - ClientData clientData; /* Ignored. */ - Tk_Window tkwin; /* Window containing canvas widget. */ - char *widgRec; /* Pointer to record for item. */ - int offset; /* Ignored. */ - Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with - * information about how to reclaim - * storage for return string. */ -{ - register Tk_Item *itemPtr = (Tk_Item *) widgRec; - - if (itemPtr->numTags == 0) { - *freeProcPtr = (Tcl_FreeProc *) NULL; - return ""; - } - if (itemPtr->numTags == 1) { - *freeProcPtr = (Tcl_FreeProc *) NULL; - return (char *) itemPtr->tagPtr[0]; - } - *freeProcPtr = TCL_DYNAMIC; - return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr); -} diff --git a/generic/tkCanvWind.c b/generic/tkCanvWind.c deleted file mode 100644 index 5839cae..0000000 --- a/generic/tkCanvWind.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * tkCanvWind.c -- - * - * This file implements window items for canvas widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvWind.c,v 1.2 1998/09/14 18:23:06 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" -#include "tkCanvas.h" - -/* - * The structure below defines the record for each window item. - */ - -typedef struct WindowItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - double x, y; /* Coordinates of positioning point for - * window. */ - Tk_Window tkwin; /* Window associated with item. NULL means - * window has been destroyed. */ - int width; /* Width to use for window (<= 0 means use - * window's requested width). */ - int height; /* Width to use for window (<= 0 means use - * window's requested width). */ - Tk_Anchor anchor; /* Where to anchor window relative to - * (x,y). */ - Tk_Canvas canvas; /* Canvas containing this item. */ -} WindowItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, - "center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, - "0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "0", Tk_Offset(WindowItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(WindowItem, tkwin), TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas, - WindowItem *winItemPtr)); -static int ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static void ScaleWinItem _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); -static int WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -static void WinItemLostSlaveProc _ANSI_ARGS_(( - ClientData clientData, Tk_Window tkwin)); -static void WinItemRequestProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void WinItemStructureProc _ANSI_ARGS_(( - ClientData clientData, XEvent *eventPtr)); -static int WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *rectPtr)); -static double WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); - -/* - * The structure below defines the window item type by means of procedures - * that can be invoked by generic item code. - */ - -Tk_ItemType tkWindowType = { - "window", /* name */ - sizeof(WindowItem), /* itemSize */ - CreateWinItem, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureWinItem, /* configureProc */ - WinItemCoords, /* coordProc */ - DeleteWinItem, /* deleteProc */ - DisplayWinItem, /* displayProc */ - 1, /* alwaysRedraw */ - WinItemToPoint, /* pointProc */ - WinItemToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ - ScaleWinItem, /* scaleProc */ - TranslateWinItem, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* cursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - - -/* - * The structure below defines the official type record for the - * placer: - */ - -static Tk_GeomMgr canvasGeomType = { - "canvas", /* name */ - WinItemRequestProc, /* requestProc */ - WinItemLostSlaveProc, /* lostSlaveProc */ -}; - -/* - *-------------------------------------------------------------- - * - * CreateWinItem -- - * - * This procedure is invoked to create a new window - * item in a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is - * left uninitialized, so it can be safely freed by the - * caller. - * - * Side effects: - * A new window item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateWinItem(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x y ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Initialize item's record. - */ - - winItemPtr->tkwin = NULL; - winItemPtr->width = 0; - winItemPtr->height = 0; - winItemPtr->anchor = TK_ANCHOR_CENTER; - winItemPtr->canvas = canvas; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &winItemPtr->y) != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureWinItem(interp, canvas, itemPtr, argc-2, argv+2, 0) - != TCL_OK) { - DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * WinItemCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on window items. See the user documentation for - * details on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -WinItemCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, winItemPtr->x, x); - Tcl_PrintDouble(interp, winItemPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) - != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &winItemPtr->y) != TCL_OK)) { - return TCL_ERROR; - } - ComputeWindowBbox(canvas, winItemPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureWinItem -- - * - * This procedure is invoked to configure various aspects - * of a window item, such as its anchor position. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Window item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - Tk_Window oldWindow; - Tk_Window canvasTkwin; - - oldWindow = winItemPtr->tkwin; - canvasTkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, argv, - (char *) winItemPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing. - */ - - if (oldWindow != winItemPtr->tkwin) { - if (oldWindow != NULL) { - Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, - WinItemStructureProc, (ClientData) winItemPtr); - Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - Tk_UnmaintainGeometry(oldWindow, canvasTkwin); - Tk_UnmapWindow(oldWindow); - } - if (winItemPtr->tkwin != NULL) { - Tk_Window ancestor, parent; - - /* - * Make sure that the canvas is either the parent of the - * window associated with the item or a descendant of that - * parent. Also, don't allow a top-level window to be - * managed inside a canvas. - */ - - parent = Tk_Parent(winItemPtr->tkwin); - for (ancestor = canvasTkwin; ; - ancestor = Tk_Parent(ancestor)) { - if (ancestor == parent) { - break; - } - if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) { - badWindow: - Tcl_AppendResult(interp, "can't use ", - Tk_PathName(winItemPtr->tkwin), - " in a window item of this canvas", (char *) NULL); - winItemPtr->tkwin = NULL; - return TCL_ERROR; - } - } - if (((Tk_FakeWin *) (winItemPtr->tkwin))->flags & TK_TOP_LEVEL) { - goto badWindow; - } - if (winItemPtr->tkwin == canvasTkwin) { - goto badWindow; - } - Tk_CreateEventHandler(winItemPtr->tkwin, StructureNotifyMask, - WinItemStructureProc, (ClientData) winItemPtr); - Tk_ManageGeometry(winItemPtr->tkwin, &canvasGeomType, - (ClientData) winItemPtr); - } - } - - ComputeWindowBbox(canvas, winItemPtr); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteWinItem -- - * - * This procedure is called to clean up the data structure - * associated with a window item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteWinItem(canvas, itemPtr, display) - Tk_Canvas canvas; /* Overall info about widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); - - if (winItemPtr->tkwin != NULL) { - Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, - WinItemStructureProc, (ClientData) winItemPtr); - Tk_ManageGeometry(winItemPtr->tkwin, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { - Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); - } - Tk_UnmapWindow(winItemPtr->tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeWindowBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a window item. - * This procedure is where the child window's placement is - * computed. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - -static void -ComputeWindowBbox(canvas, winItemPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - WindowItem *winItemPtr; /* Item whose bbox is to be - * recomputed. */ -{ - int width, height, x, y; - - x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); - y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); - - if (winItemPtr->tkwin == NULL) { - /* - * There is no window for this item yet. Just give it a 1x1 - * bounding box. Don't give it a 0x0 bounding box; there are - * strange cases where this bounding box might be used as the - * dimensions of the window, and 0x0 causes problems under X. - */ - - winItemPtr->header.x1 = x; - winItemPtr->header.x2 = winItemPtr->header.x1 + 1; - winItemPtr->header.y1 = y; - winItemPtr->header.y2 = winItemPtr->header.y1 + 1; - return; - } - - /* - * Compute dimensions of window. - */ - - width = winItemPtr->width; - if (width <= 0) { - width = Tk_ReqWidth(winItemPtr->tkwin); - if (width <= 0) { - width = 1; - } - } - height = winItemPtr->height; - if (height <= 0) { - height = Tk_ReqHeight(winItemPtr->tkwin); - if (height <= 0) { - height = 1; - } - } - - /* - * Compute location of window, using anchor information. - */ - - switch (winItemPtr->anchor) { - case TK_ANCHOR_N: - x -= width/2; - break; - case TK_ANCHOR_NE: - x -= width; - break; - case TK_ANCHOR_E: - x -= width; - y -= height/2; - break; - case TK_ANCHOR_SE: - x -= width; - y -= height; - break; - case TK_ANCHOR_S: - x -= width/2; - y -= height; - break; - case TK_ANCHOR_SW: - y -= height; - break; - case TK_ANCHOR_W: - y -= height/2; - break; - case TK_ANCHOR_NW: - break; - case TK_ANCHOR_CENTER: - x -= width/2; - y -= height/2; - break; - } - - /* - * Store the information in the item header. - */ - - winItemPtr->header.x1 = x; - winItemPtr->header.y1 = y; - winItemPtr->header.x2 = x + width; - winItemPtr->header.y2 = y + height; -} - -/* - *-------------------------------------------------------------- - * - * DisplayWinItem -- - * - * This procedure is invoked to "draw" a window item in a given - * drawable. Since the window draws itself, we needn't do any - * actual redisplay here. However, this procedure takes care - * of actually repositioning the child window so that it occupies - * the correct screen position. - * - * Results: - * None. - * - * Side effects: - * The child window's position may get changed. Note: this - * procedure gets called both when a window needs to be displayed - * and when it ceases to be visible on the screen (e.g. it was - * scrolled or moved off-screen or the enclosing canvas is - * unmapped). - * - *-------------------------------------------------------------- - */ - -static void -DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, - regionWidth, regionHeight) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int regionX, regionY, regionWidth, regionHeight; - /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - int width, height; - short x, y; - Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); - - if (winItemPtr->tkwin == NULL) { - return; - } - - Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, - (double) winItemPtr->header.y1, &x, &y); - width = winItemPtr->header.x2 - winItemPtr->header.x1; - height = winItemPtr->header.y2 - winItemPtr->header.y1; - - /* - * If the window is completely out of the visible area of the canvas - * then unmap it. This code used not to be present (why unmap the - * window if it isn't visible anyway?) but this could cause the - * window to suddenly reappear if the canvas window got resized. - */ - - if (((x + width) <= 0) || ((y + height) <= 0) - || (x >= Tk_Width(canvasTkwin)) || (y >= Tk_Height(canvasTkwin))) { - if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { - Tk_UnmapWindow(winItemPtr->tkwin); - } else { - Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); - } - return; - } - - /* - * Reposition and map the window (but in different ways depending - * on whether the canvas is the window's parent). - */ - - if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { - if ((x != Tk_X(winItemPtr->tkwin)) || (y != Tk_Y(winItemPtr->tkwin)) - || (width != Tk_Width(winItemPtr->tkwin)) - || (height != Tk_Height(winItemPtr->tkwin))) { - Tk_MoveResizeWindow(winItemPtr->tkwin, x, y, width, height); - } - Tk_MapWindow(winItemPtr->tkwin); - } else { - Tk_MaintainGeometry(winItemPtr->tkwin, canvasTkwin, x, y, - width, height); - } -} - -/* - *-------------------------------------------------------------- - * - * WinItemToPoint -- - * - * Computes the distance from a given point to a given - * rectangle, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the window. If the - * point isn't inside the window then the return value is the - * distance from the point to the window. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static double -WinItemToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - double x1, x2, y1, y2, xDiff, yDiff; - - x1 = winItemPtr->header.x1; - y1 = winItemPtr->header.y1; - x2 = winItemPtr->header.x2; - y2 = winItemPtr->header.y2; - - /* - * Point is outside rectangle. - */ - - if (pointPtr[0] < x1) { - xDiff = x1 - pointPtr[0]; - } else if (pointPtr[0] >= x2) { - xDiff = pointPtr[0] + 1 - x2; - } else { - xDiff = 0; - } - - if (pointPtr[1] < y1) { - yDiff = y1 - pointPtr[1]; - } else if (pointPtr[1] >= y2) { - yDiff = pointPtr[1] + 1 - y2; - } else { - yDiff = 0; - } - - return hypot(xDiff, yDiff); -} - -/* - *-------------------------------------------------------------- - * - * WinItemToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangle. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -WinItemToArea(canvas, itemPtr, rectPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against rectangle. */ - double *rectPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - - if ((rectPtr[2] <= winItemPtr->header.x1) - || (rectPtr[0] >= winItemPtr->header.x2) - || (rectPtr[3] <= winItemPtr->header.y1) - || (rectPtr[1] >= winItemPtr->header.y2)) { - return -1; - } - if ((rectPtr[0] <= winItemPtr->header.x1) - && (rectPtr[1] <= winItemPtr->header.y1) - && (rectPtr[2] >= winItemPtr->header.x2) - && (rectPtr[3] >= winItemPtr->header.y2)) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * ScaleWinItem -- - * - * This procedure is invoked to rescale a rectangle or oval - * item. - * - * Results: - * None. - * - * Side effects: - * The rectangle or oval referred to by itemPtr is rescaled - * so that the following transformation is applied to all - * point coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - - winItemPtr->x = originX + scaleX*(winItemPtr->x - originX); - winItemPtr->y = originY + scaleY*(winItemPtr->y - originY); - if (winItemPtr->width > 0) { - winItemPtr->width = (int) (scaleX*winItemPtr->width); - } - if (winItemPtr->height > 0) { - winItemPtr->height = (int) (scaleY*winItemPtr->height); - } - ComputeWindowBbox(canvas, winItemPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateWinItem -- - * - * This procedure is called to move a rectangle or oval by a - * given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the rectangle or oval is offset by - * (xDelta, yDelta), and the bounding box is updated in the - * generic part of the item structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateWinItem(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - WindowItem *winItemPtr = (WindowItem *) itemPtr; - - winItemPtr->x += deltaX; - winItemPtr->y += deltaY; - ComputeWindowBbox(canvas, winItemPtr); -} - -/* - *-------------------------------------------------------------- - * - * WinItemStructureProc -- - * - * This procedure is invoked whenever StructureNotify events - * occur for a window that's managed as part of a canvas window - * item. This procudure's only purpose is to clean up when - * windows are deleted. - * - * Results: - * None. - * - * Side effects: - * The window is disassociated from the window item when it is - * deleted. - * - *-------------------------------------------------------------- - */ - -static void -WinItemStructureProc(clientData, eventPtr) - ClientData clientData; /* Pointer to record describing window item. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - WindowItem *winItemPtr = (WindowItem *) clientData; - - if (eventPtr->type == DestroyNotify) { - winItemPtr->tkwin = NULL; - } -} - -/* - *-------------------------------------------------------------- - * - * WinItemRequestProc -- - * - * This procedure is invoked whenever a window that's associated - * with a window canvas item changes its requested dimensions. - * - * Results: - * None. - * - * Side effects: - * The size and location on the screen of the window may change, - * depending on the options specified for the window item. - * - *-------------------------------------------------------------- - */ - -static void -WinItemRequestProc(clientData, tkwin) - ClientData clientData; /* Pointer to record for window item. */ - Tk_Window tkwin; /* Window that changed its desired - * size. */ -{ - WindowItem *winItemPtr = (WindowItem *) clientData; - - ComputeWindowBbox(winItemPtr->canvas, winItemPtr); - DisplayWinItem(winItemPtr->canvas, (Tk_Item *) winItemPtr, - (Display *) NULL, (Drawable) None, 0, 0, 0, 0); -} - -/* - *-------------------------------------------------------------- - * - * WinItemLostSlaveProc -- - * - * This procedure is invoked by Tk whenever some other geometry - * claims control over a slave that used to be managed by us. - * - * Results: - * None. - * - * Side effects: - * Forgets all canvas-related information about the slave. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -WinItemLostSlaveProc(clientData, tkwin) - ClientData clientData; /* WindowItem structure for slave window that - * was stolen away. */ - Tk_Window tkwin; /* Tk's handle for the slave window. */ -{ - WindowItem *winItemPtr = (WindowItem *) clientData; - Tk_Window canvasTkwin = Tk_CanvasTkwin(winItemPtr->canvas); - - Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, - WinItemStructureProc, (ClientData) winItemPtr); - if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { - Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); - } - Tk_UnmapWindow(winItemPtr->tkwin); - winItemPtr->tkwin = NULL; -} diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c deleted file mode 100644 index 6574437..0000000 --- a/generic/tkCanvas.c +++ /dev/null @@ -1,3791 +0,0 @@ -/* - * tkCanvas.c -- - * - * This module implements canvas widgets for the Tk toolkit. - * A canvas displays a background and a collection of graphical - * objects such as rectangles, lines, and texts. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvas.c,v 1.2 1998/09/14 18:23:06 stanton Exp $ - */ - -#include "default.h" -#include "tkInt.h" -#include "tkPort.h" -#include "tkCanvas.h" - -/* - * See tkCanvas.h for key data structures used to implement canvases. - */ - -/* - * The structure defined below is used to keep track of a tag search - * in progress. Only the "prevPtr" field should be accessed by anyone - * other than StartTagSearch and NextItem. - */ - -typedef struct TagSearch { - TkCanvas *canvasPtr; /* Canvas widget being searched. */ - Tk_Uid tag; /* Tag to search for. 0 means return - * all items. */ - Tk_Item *prevPtr; /* Item just before last one found (or NULL - * if last one found was first in the item - * list of canvasPtr). */ - Tk_Item *currentPtr; /* Pointer to last item returned. */ - int searchOver; /* Non-zero means NextItem should always - * return NULL. */ -} TagSearch; - -/* - * Information used for argv parsing. - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0}, - {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough", - DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0}, - {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine", - DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-height", "height", "Height", - DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG, - Tk_Offset(TkCanvas, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0}, - {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground", - DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_CANVAS_INSERT_BD_COLOR, - Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_CANVAS_INSERT_BD_MONO, - Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", - DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0}, - {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", - DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0}, - {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", - DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0}, - {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion", - DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_CANVAS_SELECT_BD_COLOR, - Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement", - "ScrollIncrement", - DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement), - 0}, - {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", - DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement", - "ScrollIncrement", - DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement), - 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * List of all the item types known at present: - */ - -static Tk_ItemType *typeList = NULL; /* NULL means initialization hasn't - * been done yet. */ - -/* - * Standard item types provided by Tk: - */ - -extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType; -extern Tk_ItemType tkOvalType, tkPolygonType; -extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType; - -/* - * Various Tk_Uid's used by this module (set up during initialization): - */ - -static Tk_Uid allUid = NULL; -static Tk_Uid currentUid = NULL; - -/* - * Statistics counters: - */ - -static int numIdSearches; -static int numSlowSearches; - -/* - * Prototypes for procedures defined later in this file: - */ - -static void CanvasBindProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void CanvasBlinkProc _ANSI_ARGS_((ClientData clientData)); -static void CanvasCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr, - XEvent *eventPtr)); -static void CanvasEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int CanvasFetchSelection _ANSI_ARGS_(( - ClientData clientData, int offset, - char *buffer, int maxBytes)); -static Tk_Item * CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr, - double coords[2])); -static void CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr, - int gotFocus)); -static void CanvasLostSelection _ANSI_ARGS_(( - ClientData clientData)); -static void CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr, - Tk_Item *itemPtr, int index)); -static void CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr, - int xOrigin, int yOrigin)); -static void CanvasUpdateScrollbars _ANSI_ARGS_(( - TkCanvas *canvasPtr)); -static int CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void CanvasWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static int ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, - int flags)); -static void DestroyCanvas _ANSI_ARGS_((char *memPtr)); -static void DisplayCanvas _ANSI_ARGS_((ClientData clientData)); -static void DoItem _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Item *itemPtr, Tk_Uid tag)); -static int FindItems _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, - char *newTag, char *cmdName, char *option)); -static int FindArea _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, char **argv, Tk_Uid uid, - int enclosed)); -static double GridAlign _ANSI_ARGS_((double coord, double spacing)); -static void InitCanvas _ANSI_ARGS_((void)); -static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr)); -static void PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr, - XEvent *eventPtr)); -static void PrintScrollFractions _ANSI_ARGS_((int screen1, - int screen2, int object1, int object2, - char *string)); -static void RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, Tk_Item *prevPtr)); -static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, TagSearch *searchPtr)); - -/* - * The structure below defines canvas class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs canvasClass = { - NULL, /* createProc. */ - CanvasWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasCmd -- - * - * This procedure is invoked to process the "canvas" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_CanvasCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - TkCanvas *canvasPtr; - Tk_Window new; - - if (typeList == NULL) { - InitCanvas(); - } - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - /* - * Initialize fields that won't be initialized by ConfigureCanvas, - * or which ConfigureCanvas expects to have reasonable values - * (e.g. resource pointers). - */ - - canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas)); - canvasPtr->tkwin = new; - canvasPtr->display = Tk_Display(new); - canvasPtr->interp = interp; - canvasPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd, - (ClientData) canvasPtr, CanvasCmdDeletedProc); - canvasPtr->firstItemPtr = NULL; - canvasPtr->lastItemPtr = NULL; - canvasPtr->borderWidth = 0; - canvasPtr->bgBorder = NULL; - canvasPtr->relief = TK_RELIEF_FLAT; - canvasPtr->highlightWidth = 0; - canvasPtr->highlightBgColorPtr = NULL; - canvasPtr->highlightColorPtr = NULL; - canvasPtr->inset = 0; - canvasPtr->pixmapGC = None; - canvasPtr->width = None; - canvasPtr->height = None; - canvasPtr->confine = 0; - canvasPtr->textInfo.selBorder = NULL; - canvasPtr->textInfo.selBorderWidth = 0; - canvasPtr->textInfo.selFgColorPtr = NULL; - canvasPtr->textInfo.selItemPtr = NULL; - canvasPtr->textInfo.selectFirst = -1; - canvasPtr->textInfo.selectLast = -1; - canvasPtr->textInfo.anchorItemPtr = NULL; - canvasPtr->textInfo.selectAnchor = 0; - canvasPtr->textInfo.insertBorder = NULL; - canvasPtr->textInfo.insertWidth = 0; - canvasPtr->textInfo.insertBorderWidth = 0; - canvasPtr->textInfo.focusItemPtr = NULL; - canvasPtr->textInfo.gotFocus = 0; - canvasPtr->textInfo.cursorOn = 0; - canvasPtr->insertOnTime = 0; - canvasPtr->insertOffTime = 0; - canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - canvasPtr->xOrigin = canvasPtr->yOrigin = 0; - canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0; - canvasPtr->bindingTable = NULL; - canvasPtr->currentItemPtr = NULL; - canvasPtr->newCurrentPtr = NULL; - canvasPtr->closeEnough = 0.0; - canvasPtr->pickEvent.type = LeaveNotify; - canvasPtr->pickEvent.xcrossing.x = 0; - canvasPtr->pickEvent.xcrossing.y = 0; - canvasPtr->state = 0; - canvasPtr->xScrollCmd = NULL; - canvasPtr->yScrollCmd = NULL; - canvasPtr->scrollX1 = 0; - canvasPtr->scrollY1 = 0; - canvasPtr->scrollX2 = 0; - canvasPtr->scrollY2 = 0; - canvasPtr->regionString = NULL; - canvasPtr->xScrollIncrement = 0; - canvasPtr->yScrollIncrement = 0; - canvasPtr->scanX = 0; - canvasPtr->scanXOrigin = 0; - canvasPtr->scanY = 0; - canvasPtr->scanYOrigin = 0; - canvasPtr->hotPtr = NULL; - canvasPtr->hotPrevPtr = NULL; - canvasPtr->cursor = None; - canvasPtr->takeFocus = NULL; - canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new)); - canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new)); - canvasPtr->flags = 0; - canvasPtr->nextId = 1; - canvasPtr->psInfoPtr = NULL; - - Tk_SetClass(canvasPtr->tkwin, "Canvas"); - TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr); - Tk_CreateEventHandler(canvasPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - CanvasEventProc, (ClientData) canvasPtr); - Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask - |ButtonPressMask|ButtonReleaseMask|EnterWindowMask - |LeaveWindowMask|PointerMotionMask|VirtualEventMask, - CanvasBindProc, (ClientData) canvasPtr); - Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING, - CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING); - if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - interp->result = Tk_PathName(canvasPtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(canvasPtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * CanvasWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -CanvasWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about canvas - * widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - size_t length; - int c, result; - Tk_Item *itemPtr = NULL; /* Initialization needed only to - * prevent compiler warning. */ - TagSearch search; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) canvasPtr); - result = TCL_OK; - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " addtags tag searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0], - " addtag tag"); - } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0) - && (length >= 2)) { - int i, gotAny; - int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed - * only to prevent compiler - * warnings. */ - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox tagOrId ?tagOrId ...?\"", - (char *) NULL); - goto error; - } - gotAny = 0; - for (i = 2; i < argc; i++) { - for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if ((itemPtr->x1 >= itemPtr->x2) - || (itemPtr->y1 >= itemPtr->y2)) { - continue; - } - if (!gotAny) { - x1 = itemPtr->x1; - y1 = itemPtr->y1; - x2 = itemPtr->x2; - y2 = itemPtr->y2; - gotAny = 1; - } else { - if (itemPtr->x1 < x1) { - x1 = itemPtr->x1; - } - if (itemPtr->y1 < y1) { - y1 = itemPtr->y1; - } - if (itemPtr->x2 > x2) { - x2 = itemPtr->x2; - } - if (itemPtr->y2 > y2) { - y2 = itemPtr->y2; - } - } - } - } - if (gotAny) { - sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2); - } - } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0) - && (length >= 2)) { - ClientData object; - - if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bind tagOrId ?sequence? ?command?\"", - (char *) NULL); - goto error; - } - - /* - * Figure out what object to use for the binding (individual - * item vs. tag). - */ - - object = 0; - if (isdigit(UCHAR(argv[2][0]))) { - int id; - char *end; - - id = strtoul(argv[2], &end, 0); - if (*end != 0) { - goto bindByTag; - } - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if (itemPtr->id == id) { - object = (ClientData) itemPtr; - break; - } - } - if (object == 0) { - Tcl_AppendResult(interp, "item \"", argv[2], - "\" doesn't exist", (char *) NULL); - goto error; - } - } else { - bindByTag: - object = (ClientData) Tk_GetUid(argv[2]); - } - - /* - * Make a binding table if the canvas doesn't already have - * one. - */ - - if (canvasPtr->bindingTable == NULL) { - canvasPtr->bindingTable = Tk_CreateBindingTable(interp); - } - - if (argc == 5) { - int append = 0; - unsigned long mask; - - if (argv[4][0] == 0) { - result = Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); - goto done; - } - if (argv[4][0] == '+') { - argv[4]++; - append = 1; - } - mask = Tk_CreateBinding(interp, canvasPtr->bindingTable, - object, argv[3], argv[4], append); - if (mask == 0) { - goto error; - } - if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask - |Button2MotionMask|Button3MotionMask|Button4MotionMask - |Button5MotionMask|ButtonPressMask|ButtonReleaseMask - |EnterWindowMask|LeaveWindowMask|KeyPressMask - |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { - Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "requested illegal events; ", - "only key, button, motion, enter, leave, and virtual ", - "events may be used", (char *) NULL); - goto error; - } - } else if (argc == 4) { - char *command; - - command = Tk_GetBinding(interp, canvasPtr->bindingTable, - object, argv[3]); - if (command == NULL) { - goto error; - } - interp->result = command; - } else { - Tk_GetAllBindings(interp, canvasPtr->bindingTable, object); - } - } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) { - int x; - double grid; - - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasx screenx ?gridspacing?\"", - (char *) NULL); - goto error; - } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) { - goto error; - } - if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &grid) != TCL_OK) { - goto error; - } - } else { - grid = 0.0; - } - x += canvasPtr->xOrigin; - Tcl_PrintDouble(interp, GridAlign((double) x, grid), interp->result); - } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) { - int y; - double grid; - - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasy screeny ?gridspacing?\"", - (char *) NULL); - goto error; - } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) { - goto error; - } - if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, - argv[3], &grid) != TCL_OK) { - goto error; - } - } else { - grid = 0.0; - } - y += canvasPtr->yOrigin; - Tcl_PrintDouble(interp, GridAlign((double) y, grid), interp->result); - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); - } else { - result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0) - && (length >= 3)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " coords tagOrId ?x y x y ...?\"", - (char *) NULL); - goto error; - } - itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - if (itemPtr != NULL) { - if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - if (itemPtr->typePtr->coordProc != NULL) { - result = (*itemPtr->typePtr->coordProc)(interp, - (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3); - } - if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - } - } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0) - && (length >= 2)) { - Tk_ItemType *typePtr; - Tk_ItemType *matchPtr = NULL; - Tk_Item *itemPtr; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " create type ?arg arg ...?\"", (char *) NULL); - goto error; - } - c = argv[2][0]; - length = strlen(argv[2]); - for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) { - if ((c == typePtr->name[0]) - && (strncmp(argv[2], typePtr->name, length) == 0)) { - if (matchPtr != NULL) { - badType: - Tcl_AppendResult(interp, - "unknown or ambiguous item type \"", - argv[2], "\"", (char *) NULL); - goto error; - } - matchPtr = typePtr; - } - } - if (matchPtr == NULL) { - goto badType; - } - typePtr = matchPtr; - itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize); - itemPtr->id = canvasPtr->nextId; - canvasPtr->nextId++; - itemPtr->tagPtr = itemPtr->staticTagSpace; - itemPtr->tagSpace = TK_TAG_SPACE; - itemPtr->numTags = 0; - itemPtr->typePtr = typePtr; - if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argc-3, argv+3) != TCL_OK) { - ckfree((char *) itemPtr); - goto error; - } - itemPtr->nextPtr = NULL; - canvasPtr->hotPtr = itemPtr; - canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr; - if (canvasPtr->lastItemPtr == NULL) { - canvasPtr->firstItemPtr = itemPtr; - } else { - canvasPtr->lastItemPtr->nextPtr = itemPtr; - } - canvasPtr->lastItemPtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - canvasPtr->flags |= REPICK_NEEDED; - sprintf(interp->result, "%d", itemPtr->id); - } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0) - && (length >= 2)) { - int first, last; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dchars tagOrId first ?last?\"", - (char *) NULL); - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if ((itemPtr->typePtr->indexProc == NULL) - || (itemPtr->typePtr->dCharsProc == NULL)) { - continue; - } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &first) != TCL_OK) { - goto error; - } - if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, - (Tk_Canvas) canvasPtr, itemPtr, argv[4], &last) - != TCL_OK) { - goto error; - } - } else { - last = first; - } - - /* - * Redraw both item's old and new areas: it's possible - * that a delete could result in a new area larger than - * the old area. - */ - - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr, - itemPtr, first, last); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0) - && (length >= 2)) { - int i; - - for (i = 2; i < argc; i++) { - for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - if (canvasPtr->bindingTable != NULL) { - Tk_DeleteAllBindings(canvasPtr->bindingTable, - (ClientData) itemPtr); - } - (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr, - canvasPtr->display); - if (itemPtr->tagPtr != itemPtr->staticTagSpace) { - ckfree((char *) itemPtr->tagPtr); - } - if (search.prevPtr == NULL) { - canvasPtr->firstItemPtr = itemPtr->nextPtr; - if (canvasPtr->firstItemPtr == NULL) { - canvasPtr->lastItemPtr = NULL; - } - } else { - search.prevPtr->nextPtr = itemPtr->nextPtr; - } - if (canvasPtr->lastItemPtr == itemPtr) { - canvasPtr->lastItemPtr = search.prevPtr; - } - ckfree((char *) itemPtr); - if (itemPtr == canvasPtr->currentItemPtr) { - canvasPtr->currentItemPtr = NULL; - canvasPtr->flags |= REPICK_NEEDED; - } - if (itemPtr == canvasPtr->newCurrentPtr) { - canvasPtr->newCurrentPtr = NULL; - canvasPtr->flags |= REPICK_NEEDED; - } - if (itemPtr == canvasPtr->textInfo.focusItemPtr) { - canvasPtr->textInfo.focusItemPtr = NULL; - } - if (itemPtr == canvasPtr->textInfo.selItemPtr) { - canvasPtr->textInfo.selItemPtr = NULL; - } - if ((itemPtr == canvasPtr->hotPtr) - || (itemPtr == canvasPtr->hotPrevPtr)) { - canvasPtr->hotPtr = NULL; - } - } - } - } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0) - && (length >= 2)) { - Tk_Uid tag; - int i; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dtag tagOrId ?tagToDelete?\"", - (char *) NULL); - goto error; - } - if (argc == 4) { - tag = Tk_GetUid(argv[3]); - } else { - tag = Tk_GetUid(argv[2]); - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - for (i = itemPtr->numTags-1; i >= 0; i--) { - if (itemPtr->tagPtr[i] == tag) { - itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; - itemPtr->numTags--; - } - } - } - } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0) - && (length >= 2)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " find searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL, - argv[0]," find"); - } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0) - && (length >= 2)) { - if (argc > 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " focus ?tagOrId?\"", - (char *) NULL); - goto error; - } - itemPtr = canvasPtr->textInfo.focusItemPtr; - if (argc == 2) { - if (itemPtr != NULL) { - sprintf(interp->result, "%d", itemPtr->id); - } - goto done; - } - if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - if (argv[2][0] == 0) { - canvasPtr->textInfo.focusItemPtr = NULL; - goto done; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if (itemPtr->typePtr->icursorProc != NULL) { - break; - } - } - if (itemPtr == NULL) { - goto done; - } - canvasPtr->textInfo.focusItemPtr = itemPtr; - if (canvasPtr->textInfo.gotFocus) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " gettags tagOrId\"", (char *) NULL); - goto error; - } - itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - if (itemPtr != NULL) { - int i; - for (i = 0; i < itemPtr->numTags; i++) { - Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]); - } - } - } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0) - && (length >= 2)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " icursor tagOrId index\"", - (char *) NULL); - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if ((itemPtr->typePtr->indexProc == NULL) - || (itemPtr->typePtr->icursorProc == NULL)) { - goto done; - } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; - } - (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr, - index); - if ((itemPtr == canvasPtr->textInfo.focusItemPtr) - && (canvasPtr->textInfo.cursorOn)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index tagOrId string\"", - (char *) NULL); - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if (itemPtr->typePtr->indexProc != NULL) { - break; - } - } - if (itemPtr == NULL) { - Tcl_AppendResult(interp, "can't find an indexable item \"", - argv[2], "\"", (char *) NULL); - goto error; - } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; - } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int beforeThis; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert tagOrId beforeThis string\"", - (char *) NULL); - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if ((itemPtr->typePtr->indexProc == NULL) - || (itemPtr->typePtr->insertProc == NULL)) { - continue; - } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &beforeThis) != TCL_OK) { - goto error; - } - - /* - * Redraw both item's old and new areas: it's possible - * that an insertion could result in a new area either - * larger or smaller than the old area. - */ - - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, - itemPtr, beforeThis, argv[4]); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, - itemPtr->y1, itemPtr->x2, itemPtr->y2); - } - } else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0) - && (length >= 6)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemcget tagOrId option\"", - (char *) NULL); - return TCL_ERROR; - } - itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - if (itemPtr != NULL) { - result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin, - itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); - } - } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0) - && (length >= 6)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemconfigure tagOrId ?option value ...?\"", - (char *) NULL); - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if (argc == 3) { - result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, - itemPtr->typePtr->configSpecs, (char *) itemPtr, - (char *) NULL, 0); - } else if (argc == 4) { - result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, - itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); - } else { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - result = (*itemPtr->typePtr->configProc)(interp, - (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3, - TK_CONFIG_ARGV_ONLY); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - canvasPtr->flags |= REPICK_NEEDED; - } - if ((result != TCL_OK) || (argc < 5)) { - break; - } - } - } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) { - Tk_Item *prevPtr; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " lower tagOrId ?belowThis?\"", - (char *) NULL); - goto error; - } - - /* - * First find the item just after which we'll insert the - * named items. - */ - - if (argc == 3) { - prevPtr = NULL; - } else { - prevPtr = StartTagSearch(canvasPtr, argv[3], &search); - if (prevPtr != NULL) { - prevPtr = search.prevPtr; - } else { - Tcl_AppendResult(interp, "tag \"", argv[3], - "\" doesn't match any items", (char *) NULL); - goto error; - } - } - RelinkItems(canvasPtr, argv[2], prevPtr); - } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) { - double xAmount, yAmount; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " move tagOrId xAmount yAmount\"", - (char *) NULL); - goto error; - } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp, - (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) { - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr, - itemPtr, xAmount, yAmount); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - canvasPtr->flags |= REPICK_NEEDED; - } - } else if ((c == 'p') && (strncmp(argv[1], "postscript", length) == 0)) { - result = TkCanvPostscriptCmd(canvasPtr, interp, argc, argv); - } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) { - Tk_Item *prevPtr; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " raise tagOrId ?aboveThis?\"", - (char *) NULL); - goto error; - } - - /* - * First find the item just after which we'll insert the - * named items. - */ - - if (argc == 3) { - prevPtr = canvasPtr->lastItemPtr; - } else { - prevPtr = NULL; - for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - prevPtr = itemPtr; - } - if (prevPtr == NULL) { - Tcl_AppendResult(interp, "tagOrId \"", argv[3], - "\" doesn't match any items", (char *) NULL); - goto error; - } - } - RelinkItems(canvasPtr, argv[2], prevPtr); - } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0) - && (length >= 3)) { - double xOrigin, yOrigin, xScale, yScale; - - if (argc != 7) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"", - (char *) NULL); - goto error; - } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, - argv[3], &xOrigin) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, - argv[4], &yOrigin) != TCL_OK) - || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK) - || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) { - goto error; - } - if ((xScale == 0.0) || (yScale == 0.0)) { - interp->result = "scale factor cannot be zero"; - goto error; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr, - itemPtr, xOrigin, yOrigin, xScale, yScale); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - canvasPtr->flags |= REPICK_NEEDED; - } - } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0) - && (length >= 3)) { - int x, y; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){ - goto error; - } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { - canvasPtr->scanX = x; - canvasPtr->scanXOrigin = canvasPtr->xOrigin; - canvasPtr->scanY = y; - canvasPtr->scanYOrigin = canvasPtr->yOrigin; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { - int newXOrigin, newYOrigin, tmp; - - /* - * Compute a new view origin for the canvas, amplifying the - * mouse motion. - */ - - tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX) - - canvasPtr->scrollX1; - newXOrigin = canvasPtr->scrollX1 + tmp; - tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY) - - canvasPtr->scrollY1; - newYOrigin = canvasPtr->scrollY1 + tmp; - CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; - } - } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) - && (length >= 2)) { - int index; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL); - goto error; - } - if (argc >= 4) { - for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if ((itemPtr->typePtr->indexProc != NULL) - && (itemPtr->typePtr->selectionProc != NULL)){ - break; - } - } - if (itemPtr == NULL) { - Tcl_AppendResult(interp, - "can't find an indexable and selectable item \"", - argv[3], "\"", (char *) NULL); - goto error; - } - } - if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[4], &index) != TCL_OK) { - goto error; - } - } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select adjust tagOrId index\"", - (char *) NULL); - goto error; - } - if (canvasPtr->textInfo.selItemPtr == itemPtr) { - if (index < (canvasPtr->textInfo.selectFirst - + canvasPtr->textInfo.selectLast)/2) { - canvasPtr->textInfo.selectAnchor = - canvasPtr->textInfo.selectLast + 1; - } else { - canvasPtr->textInfo.selectAnchor = - canvasPtr->textInfo.selectFirst; - } - } - CanvasSelectTo(canvasPtr, itemPtr, index); - } else if ((c == 'c') && (argv[2] != NULL) - && (strncmp(argv[2], "clear", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select clear\"", (char *) NULL); - goto error; - } - if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); - canvasPtr->textInfo.selItemPtr = NULL; - } - goto done; - } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select from tagOrId index\"", - (char *) NULL); - goto error; - } - canvasPtr->textInfo.anchorItemPtr = itemPtr; - canvasPtr->textInfo.selectAnchor = index; - } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select item\"", (char *) NULL); - goto error; - } - if (canvasPtr->textInfo.selItemPtr != NULL) { - sprintf(interp->result, "%d", - canvasPtr->textInfo.selItemPtr->id); - } - } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select to tagOrId index\"", - (char *) NULL); - goto error; - } - CanvasSelectTo(canvasPtr, itemPtr, index); - } else { - Tcl_AppendResult(interp, "bad select option \"", argv[2], - "\": must be adjust, clear, from, item, or to", - (char *) NULL); - goto error; - } - } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " type tag\"", (char *) NULL); - goto error; - } - itemPtr = StartTagSearch(canvasPtr, argv[2], &search); - if (itemPtr != NULL) { - interp->result = itemPtr->typePtr->name; - } - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - int count, type; - int newX = 0; /* Initialization needed only to prevent - * gcc warnings. */ - double fraction; - - if (argc == 2) { - PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin) - - canvasPtr->inset, canvasPtr->scrollX1, - canvasPtr->scrollX2, interp->result); - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - newX = canvasPtr->scrollX1 - canvasPtr->inset - + (int) (fraction * (canvasPtr->scrollX2 - - canvasPtr->scrollX1) + 0.5); - break; - case TK_SCROLL_PAGES: - newX = (int) (canvasPtr->xOrigin + count * .9 - * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset)); - break; - case TK_SCROLL_UNITS: - if (canvasPtr->xScrollIncrement > 0) { - newX = canvasPtr->xOrigin - + count*canvasPtr->xScrollIncrement; - } else { - newX = (int) (canvasPtr->xOrigin + count * .1 - * (Tk_Width(canvasPtr->tkwin) - - 2*canvasPtr->inset)); - } - break; - } - CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin); - } - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) { - int count, type; - int newY = 0; /* Initialization needed only to prevent - * gcc warnings. */ - double fraction; - - if (argc == 2) { - PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset, - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin) - - canvasPtr->inset, canvasPtr->scrollY1, - canvasPtr->scrollY2, interp->result); - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - newY = canvasPtr->scrollY1 - canvasPtr->inset - + (int) (fraction*(canvasPtr->scrollY2 - - canvasPtr->scrollY1) + 0.5); - break; - case TK_SCROLL_PAGES: - newY = (int) (canvasPtr->yOrigin + count * .9 - * (Tk_Height(canvasPtr->tkwin) - - 2*canvasPtr->inset)); - break; - case TK_SCROLL_UNITS: - if (canvasPtr->yScrollIncrement > 0) { - newY = canvasPtr->yOrigin - + count*canvasPtr->yScrollIncrement; - } else { - newY = (int) (canvasPtr->yOrigin + count * .1 - * (Tk_Height(canvasPtr->tkwin) - - 2*canvasPtr->inset)); - } - break; - } - CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be addtag, bbox, bind, ", - "canvasx, canvasy, cget, configure, coords, create, ", - "dchars, delete, dtag, find, focus, ", - "gettags, icursor, index, insert, itemcget, itemconfigure, ", - "lower, move, postscript, raise, scale, scan, ", - "select, type, xview, or yview", - (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) canvasPtr); - return result; - - error: - Tcl_Release((ClientData) canvasPtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyCanvas -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a canvas at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the canvas is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyCanvas(memPtr) - char *memPtr; /* Info about canvas widget. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) memPtr; - Tk_Item *itemPtr; - - /* - * Free up all of the items in the canvas. - */ - - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = canvasPtr->firstItemPtr) { - canvasPtr->firstItemPtr = itemPtr->nextPtr; - (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr, - canvasPtr->display); - if (itemPtr->tagPtr != itemPtr->staticTagSpace) { - ckfree((char *) itemPtr->tagPtr); - } - ckfree((char *) itemPtr); - } - - /* - * Free up all the stuff that requires special handling, - * then let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (canvasPtr->pixmapGC != None) { - Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); - } - Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); - if (canvasPtr->bindingTable != NULL) { - Tk_DeleteBindingTable(canvasPtr->bindingTable); - } - Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0); - ckfree((char *) canvasPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureCanvas -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a canvas widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for canvasPtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureCanvas(interp, canvasPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - TkCanvas *canvasPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - XGCValues gcValues; - GC new; - - if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs, - argc, argv, (char *) canvasPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few options need special processing, such as setting the - * background from a 3-D border and creating a GC for copying - * bits to the screen. - */ - - Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder); - - if (canvasPtr->highlightWidth < 0) { - canvasPtr->highlightWidth = 0; - } - canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth; - - gcValues.function = GXcopy; - gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; - gcValues.graphics_exposures = False; - new = Tk_GetGC(canvasPtr->tkwin, - GCFunction|GCForeground|GCGraphicsExposures, &gcValues); - if (canvasPtr->pixmapGC != None) { - Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); - } - canvasPtr->pixmapGC = new; - - /* - * Reset the desired dimensions for the window. - */ - - Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset, - canvasPtr->height + 2*canvasPtr->inset); - - /* - * Restart the cursor timing sequence in case the on-time or off-time - * just changed. - */ - - if (canvasPtr->textInfo.gotFocus) { - CanvasFocusProc(canvasPtr, 1); - } - - /* - * Recompute the scroll region. - */ - - canvasPtr->scrollX1 = 0; - canvasPtr->scrollY1 = 0; - canvasPtr->scrollX2 = 0; - canvasPtr->scrollY2 = 0; - if (canvasPtr->regionString != NULL) { - int argc2; - char **argv2; - - if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString, - &argc2, &argv2) != TCL_OK) { - return TCL_ERROR; - } - if (argc2 != 4) { - Tcl_AppendResult(interp, "bad scrollRegion \"", - canvasPtr->regionString, "\"", (char *) NULL); - badRegion: - ckfree(canvasPtr->regionString); - ckfree((char *) argv2); - canvasPtr->regionString = NULL; - return TCL_ERROR; - } - if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, - argv2[0], &canvasPtr->scrollX1) != TCL_OK) - || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, - argv2[1], &canvasPtr->scrollY1) != TCL_OK) - || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, - argv2[2], &canvasPtr->scrollX2) != TCL_OK) - || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, - argv2[3], &canvasPtr->scrollY2) != TCL_OK)) { - goto badRegion; - } - ckfree((char *) argv2); - } - - /* - * Reset the canvas's origin (this is a no-op unless confine - * mode has just been turned on or the scroll region has changed). - */ - - CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin); - canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->xOrigin, canvasPtr->yOrigin, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * CanvasWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Configures all items in the canvas with a empty argc/argv, for - * the side effect of causing all the items to recompute their - * geometry and to be redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -CanvasWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - TkCanvas *canvasPtr; - Tk_Item *itemPtr; - int result; - - canvasPtr = (TkCanvas *) instanceData; - itemPtr = canvasPtr->firstItemPtr; - for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { - result = (*itemPtr->typePtr->configProc)(canvasPtr->interp, - (Tk_Canvas) canvasPtr, itemPtr, 0, NULL, - TK_CONFIG_ARGV_ONLY); - if (result != TCL_OK) { - Tcl_ResetResult(canvasPtr->interp); - } - } - canvasPtr->flags |= REPICK_NEEDED; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->xOrigin, canvasPtr->yOrigin, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); -} - -/* - *-------------------------------------------------------------- - * - * DisplayCanvas -- - * - * This procedure redraws the contents of a canvas window. - * It is invoked as a do-when-idle handler, so it only runs - * when there's nothing else for the application to do. - * - * Results: - * None. - * - * Side effects: - * Information appears on the screen. - * - *-------------------------------------------------------------- - */ - -static void -DisplayCanvas(clientData) - ClientData clientData; /* Information about widget. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - Tk_Window tkwin = canvasPtr->tkwin; - Tk_Item *itemPtr; - Pixmap pixmap; - int screenX1, screenX2, screenY1, screenY2, width, height; - - if (canvasPtr->tkwin == NULL) { - return; - } - if (!Tk_IsMapped(tkwin)) { - goto done; - } - - /* - * Choose a new current item if that is needed (this could cause - * event handlers to be invoked). - */ - - while (canvasPtr->flags & REPICK_NEEDED) { - Tcl_Preserve((ClientData) canvasPtr); - canvasPtr->flags &= ~REPICK_NEEDED; - PickCurrentItem(canvasPtr, &canvasPtr->pickEvent); - tkwin = canvasPtr->tkwin; - Tcl_Release((ClientData) canvasPtr); - if (tkwin == NULL) { - return; - } - } - - /* - * Compute the intersection between the area that needs redrawing - * and the area that's visible on the screen. - */ - - if ((canvasPtr->redrawX1 < canvasPtr->redrawX2) - && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) { - screenX1 = canvasPtr->xOrigin + canvasPtr->inset; - screenY1 = canvasPtr->yOrigin + canvasPtr->inset; - screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset; - screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset; - if (canvasPtr->redrawX1 > screenX1) { - screenX1 = canvasPtr->redrawX1; - } - if (canvasPtr->redrawY1 > screenY1) { - screenY1 = canvasPtr->redrawY1; - } - if (canvasPtr->redrawX2 < screenX2) { - screenX2 = canvasPtr->redrawX2; - } - if (canvasPtr->redrawY2 < screenY2) { - screenY2 = canvasPtr->redrawY2; - } - if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) { - goto borders; - } - - /* - * Redrawing is done in a temporary pixmap that is allocated - * here and freed at the end of the procedure. All drawing - * is done to the pixmap, and the pixmap is copied to the - * screen at the end of the procedure. The temporary pixmap - * serves two purposes: - * - * 1. It provides a smoother visual effect (no clearing and - * gradual redraw will be visible to users). - * 2. It allows us to redraw only the objects that overlap - * the redraw area. Otherwise incorrect results could - * occur from redrawing things that stick outside of - * the redraw area (we'd have to redraw everything in - * order to make the overlaps look right). - * - * Some tricky points about the pixmap: - * - * 1. We only allocate a large enough pixmap to hold the - * area that has to be redisplayed. This saves time in - * in the X server for large objects that cover much - * more than the area being redisplayed: only the area - * of the pixmap will actually have to be redrawn. - * 2. Some X servers (e.g. the one for DECstations) have troubles - * with characters that overlap an edge of the pixmap (on the - * DEC servers, as of 8/18/92, such characters are drawn one - * pixel too far to the right). To handle this problem, - * make the pixmap a bit larger than is absolutely needed - * so that for normal-sized fonts the characters that overlap - * the edge of the pixmap will be outside the area we care - * about. - */ - - canvasPtr->drawableXOrigin = screenX1 - 30; - canvasPtr->drawableYOrigin = screenY1 - 30; - pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), - (screenX2 + 30 - canvasPtr->drawableXOrigin), - (screenY2 + 30 - canvasPtr->drawableYOrigin), - Tk_Depth(tkwin)); - - /* - * Clear the area to be redrawn. - */ - - width = screenX2 - screenX1; - height = screenY2 - screenY1; - - XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC, - screenX1 - canvasPtr->drawableXOrigin, - screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width, - (unsigned int) height); - - /* - * Scan through the item list, redrawing those items that need it. - * An item must be redraw if either (a) it intersects the smaller - * on-screen area or (b) it intersects the full canvas area and its - * type requests that it be redrawn always (e.g. so subwindows can - * be unmapped when they move off-screen). - */ - - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if ((itemPtr->x1 >= screenX2) - || (itemPtr->y1 >= screenY2) - || (itemPtr->x2 < screenX1) - || (itemPtr->y2 < screenY1)) { - if (!itemPtr->typePtr->alwaysRedraw - || (itemPtr->x1 >= canvasPtr->redrawX2) - || (itemPtr->y1 >= canvasPtr->redrawY2) - || (itemPtr->x2 < canvasPtr->redrawX1) - || (itemPtr->y2 < canvasPtr->redrawY1)) { - continue; - } - } - (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, - canvasPtr->display, pixmap, screenX1, screenY1, width, - height); - } - - /* - * Copy from the temporary pixmap to the screen, then free up - * the temporary pixmap. - */ - - XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), - canvasPtr->pixmapGC, - screenX1 - canvasPtr->drawableXOrigin, - screenY1 - canvasPtr->drawableYOrigin, - (unsigned) (screenX2 - screenX1), - (unsigned) (screenY2 - screenY1), - screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin); - Tk_FreePixmap(Tk_Display(tkwin), pixmap); - } - - /* - * Draw the window borders, if needed. - */ - - borders: - if (canvasPtr->flags & REDRAW_BORDERS) { - canvasPtr->flags &= ~REDRAW_BORDERS; - if (canvasPtr->borderWidth > 0) { - Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), - canvasPtr->bgBorder, canvasPtr->highlightWidth, - canvasPtr->highlightWidth, - Tk_Width(tkwin) - 2*canvasPtr->highlightWidth, - Tk_Height(tkwin) - 2*canvasPtr->highlightWidth, - canvasPtr->borderWidth, canvasPtr->relief); - } - if (canvasPtr->highlightWidth != 0) { - GC gc; - - if (canvasPtr->textInfo.gotFocus) { - gc = Tk_GCForColor(canvasPtr->highlightColorPtr, - Tk_WindowId(tkwin)); - } else { - gc = Tk_GCForColor(canvasPtr->highlightBgColorPtr, - Tk_WindowId(tkwin)); - } - Tk_DrawFocusHighlight(tkwin, gc, canvasPtr->highlightWidth, - Tk_WindowId(tkwin)); - } - } - - done: - canvasPtr->flags &= ~REDRAW_PENDING; - canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0; - canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0; - if (canvasPtr->flags & UPDATE_SCROLLBARS) { - CanvasUpdateScrollbars(canvasPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * CanvasEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on canvases. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -CanvasEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - - if (eventPtr->type == Expose) { - int x, y; - - x = eventPtr->xexpose.x + canvasPtr->xOrigin; - y = eventPtr->xexpose.y + canvasPtr->yOrigin; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y, - x + eventPtr->xexpose.width, - y + eventPtr->xexpose.height); - if ((eventPtr->xexpose.x < canvasPtr->inset) - || (eventPtr->xexpose.y < canvasPtr->inset) - || ((eventPtr->xexpose.x + eventPtr->xexpose.width) - > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset)) - || ((eventPtr->xexpose.y + eventPtr->xexpose.height) - > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) { - canvasPtr->flags |= REDRAW_BORDERS; - } - } else if (eventPtr->type == DestroyNotify) { - if (canvasPtr->tkwin != NULL) { - canvasPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(canvasPtr->interp, - canvasPtr->widgetCmd); - } - if (canvasPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr); - } - Tcl_EventuallyFree((ClientData) canvasPtr, DestroyCanvas); - } else if (eventPtr->type == ConfigureNotify) { - canvasPtr->flags |= UPDATE_SCROLLBARS; - - /* - * The call below is needed in order to recenter the canvas if - * it's confined and its scroll region is smaller than the window. - */ - - CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin, - canvasPtr->yOrigin, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); - canvasPtr->flags |= REDRAW_BORDERS; - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - CanvasFocusProc(canvasPtr, 1); - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - CanvasFocusProc(canvasPtr, 0); - } - } else if (eventPtr->type == UnmapNotify) { - Tk_Item *itemPtr; - - /* - * Special hack: if the canvas is unmapped, then must notify - * all items with "alwaysRedraw" set, so that they know that - * they are no longer displayed. - */ - - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if (itemPtr->typePtr->alwaysRedraw) { - (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, - itemPtr, canvasPtr->display, None, 0, 0, 0, 0); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * CanvasCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -CanvasCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - Tk_Window tkwin = canvasPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - canvasPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_CanvasEventuallyRedraw -- - * - * Arrange for part or all of a canvas widget to redrawn at - * some convenient time in the future. - * - * Results: - * None. - * - * Side effects: - * The screen will eventually be refreshed. - * - *-------------------------------------------------------------- - */ - -void -Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2) - Tk_Canvas canvas; /* Information about widget. */ - int x1, y1; /* Upper left corner of area to redraw. - * Pixels on edge are redrawn. */ - int x2, y2; /* Lower right corner of area to redraw. - * Pixels on edge are not redrawn. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) canvas; - if ((x1 == x2) || (y1 == y2)) { - return; - } - if (canvasPtr->flags & REDRAW_PENDING) { - if (x1 <= canvasPtr->redrawX1) { - canvasPtr->redrawX1 = x1; - } - if (y1 <= canvasPtr->redrawY1) { - canvasPtr->redrawY1 = y1; - } - if (x2 >= canvasPtr->redrawX2) { - canvasPtr->redrawX2 = x2; - } - if (y2 >= canvasPtr->redrawY2) { - canvasPtr->redrawY2 = y2; - } - } else { - canvasPtr->redrawX1 = x1; - canvasPtr->redrawY1 = y1; - canvasPtr->redrawX2 = x2; - canvasPtr->redrawY2 = y2; - Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); - canvasPtr->flags |= REDRAW_PENDING; - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_CreateItemType -- - * - * This procedure may be invoked to add a new kind of canvas - * element to the core item types supported by Tk. - * - * Results: - * None. - * - * Side effects: - * From now on, the new item type will be useable in canvas - * widgets (e.g. typePtr->name can be used as the item type - * in "create" widget commands). If there was already a - * type with the same name as in typePtr, it is replaced with - * the new type. - * - *-------------------------------------------------------------- - */ - -void -Tk_CreateItemType(typePtr) - Tk_ItemType *typePtr; /* Information about item type; - * storage must be statically - * allocated (must live forever). */ -{ - Tk_ItemType *typePtr2, *prevPtr; - - if (typeList == NULL) { - InitCanvas(); - } - - /* - * If there's already an item type with the given name, remove it. - */ - - for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL; - prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { - if (strcmp(typePtr2->name, typePtr->name) == 0) { - if (prevPtr == NULL) { - typeList = typePtr2->nextPtr; - } else { - prevPtr->nextPtr = typePtr2->nextPtr; - } - break; - } - } - typePtr->nextPtr = typeList; - typeList = typePtr; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetItemTypes -- - * - * This procedure returns a pointer to the list of all item - * types. - * - * Results: - * The return value is a pointer to the first in the list - * of item types currently supported by canvases. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_ItemType * -Tk_GetItemTypes() -{ - if (typeList == NULL) { - InitCanvas(); - } - return typeList; -} - -/* - *-------------------------------------------------------------- - * - * InitCanvas -- - * - * This procedure is invoked to perform once-only-ever - * initialization for the module, such as setting up - * the type table. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -InitCanvas() -{ - if (typeList != NULL) { - return; - } - typeList = &tkRectangleType; - tkRectangleType.nextPtr = &tkTextType; - tkTextType.nextPtr = &tkLineType; - tkLineType.nextPtr = &tkPolygonType; - tkPolygonType.nextPtr = &tkImageType; - tkImageType.nextPtr = &tkOvalType; - tkOvalType.nextPtr = &tkBitmapType; - tkBitmapType.nextPtr = &tkArcType; - tkArcType.nextPtr = &tkWindowType; - tkWindowType.nextPtr = NULL; - allUid = Tk_GetUid("all"); - currentUid = Tk_GetUid("current"); -} - -/* - *-------------------------------------------------------------- - * - * StartTagSearch -- - * - * This procedure is called to initiate an enumeration of - * all items in a given canvas that contain a given tag. - * - * Results: - * The return value is a pointer to the first item in - * canvasPtr that matches tag, or NULL if there is no - * such item. The information at *searchPtr is initialized - * such that successive calls to NextItem will return - * successive items that match tag. - * - * Side effects: - * SearchPtr is linked into a list of searches in progress - * on canvasPtr, so that elements can safely be deleted - * while the search is in progress. EndTagSearch must be - * called at the end of the search to unlink searchPtr from - * this list. - * - *-------------------------------------------------------------- - */ - -static Tk_Item * -StartTagSearch(canvasPtr, tag, searchPtr) - TkCanvas *canvasPtr; /* Canvas whose items are to be - * searched. */ - char *tag; /* String giving tag value. */ - TagSearch *searchPtr; /* Record describing tag search; - * will be initialized here. */ -{ - int id; - Tk_Item *itemPtr, *prevPtr; - Tk_Uid *tagPtr; - Tk_Uid uid; - int count; - - /* - * Initialize the search. - */ - - searchPtr->canvasPtr = canvasPtr; - searchPtr->searchOver = 0; - - /* - * Find the first matching item in one of several ways. If the tag - * is a number then it selects the single item with the matching - * identifier. In this case see if the item being requested is the - * hot item, in which case the search can be skipped. - */ - - if (isdigit(UCHAR(*tag))) { - char *end; - - numIdSearches++; - id = strtoul(tag, &end, 0); - if (*end == 0) { - itemPtr = canvasPtr->hotPtr; - prevPtr = canvasPtr->hotPrevPtr; - if ((itemPtr == NULL) || (itemPtr->id != id) || (prevPtr == NULL) - || (prevPtr->nextPtr != itemPtr)) { - numSlowSearches++; - for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr; - itemPtr != NULL; - prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) { - if (itemPtr->id == id) { - break; - } - } - } - searchPtr->prevPtr = prevPtr; - searchPtr->searchOver = 1; - canvasPtr->hotPtr = itemPtr; - canvasPtr->hotPrevPtr = prevPtr; - return itemPtr; - } - } - - searchPtr->tag = uid = Tk_GetUid(tag); - if (uid == allUid) { - - /* - * All items match. - */ - - searchPtr->tag = NULL; - searchPtr->prevPtr = NULL; - searchPtr->currentPtr = canvasPtr->firstItemPtr; - return canvasPtr->firstItemPtr; - } - - /* - * None of the above. Search for an item with a matching tag. - */ - - for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) { - for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; - count > 0; tagPtr++, count--) { - if (*tagPtr == uid) { - searchPtr->prevPtr = prevPtr; - searchPtr->currentPtr = itemPtr; - return itemPtr; - } - } - } - searchPtr->prevPtr = prevPtr; - searchPtr->searchOver = 1; - return NULL; -} - -/* - *-------------------------------------------------------------- - * - * NextItem -- - * - * This procedure returns successive items that match a given - * tag; it should be called only after StartTagSearch has been - * used to begin a search. - * - * Results: - * The return value is a pointer to the next item that matches - * the tag specified to StartTagSearch, or NULL if no such - * item exists. *SearchPtr is updated so that the next call - * to this procedure will return the next item. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static Tk_Item * -NextItem(searchPtr) - TagSearch *searchPtr; /* Record describing search in - * progress. */ -{ - Tk_Item *itemPtr, *prevPtr; - int count; - Tk_Uid uid; - Tk_Uid *tagPtr; - - /* - * Find next item in list (this may not actually be a suitable - * one to return), and return if there are no items left. - */ - - prevPtr = searchPtr->prevPtr; - if (prevPtr == NULL) { - itemPtr = searchPtr->canvasPtr->firstItemPtr; - } else { - itemPtr = prevPtr->nextPtr; - } - if ((itemPtr == NULL) || (searchPtr->searchOver)) { - searchPtr->searchOver = 1; - return NULL; - } - if (itemPtr != searchPtr->currentPtr) { - /* - * The structure of the list has changed. Probably the - * previously-returned item was removed from the list. - * In this case, don't advance prevPtr; just return - * its new successor (i.e. do nothing here). - */ - } else { - prevPtr = itemPtr; - itemPtr = prevPtr->nextPtr; - } - - /* - * Handle special case of "all" search by returning next item. - */ - - uid = searchPtr->tag; - if (uid == NULL) { - searchPtr->prevPtr = prevPtr; - searchPtr->currentPtr = itemPtr; - return itemPtr; - } - - /* - * Look for an item with a particular tag. - */ - - for ( ; itemPtr != NULL; prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) { - for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; - count > 0; tagPtr++, count--) { - if (*tagPtr == uid) { - searchPtr->prevPtr = prevPtr; - searchPtr->currentPtr = itemPtr; - return itemPtr; - } - } - } - searchPtr->prevPtr = prevPtr; - searchPtr->searchOver = 1; - return NULL; -} - -/* - *-------------------------------------------------------------- - * - * DoItem -- - * - * This is a utility procedure called by FindItems. It - * either adds itemPtr's id to the result forming in interp, - * or it adds a new tag to itemPtr, depending on the value - * of tag. - * - * Results: - * None. - * - * Side effects: - * If tag is NULL then itemPtr's id is added as a list element - * to interp->result; otherwise tag is added to itemPtr's - * list of tags. - * - *-------------------------------------------------------------- - */ - -static void -DoItem(interp, itemPtr, tag) - Tcl_Interp *interp; /* Interpreter in which to (possibly) - * record item id. */ - Tk_Item *itemPtr; /* Item to (possibly) modify. */ - Tk_Uid tag; /* Tag to add to those already - * present for item, or NULL. */ -{ - Tk_Uid *tagPtr; - int count; - - /* - * Handle the "add-to-result" case and return, if appropriate. - */ - - if (tag == NULL) { - char msg[30]; - sprintf(msg, "%d", itemPtr->id); - Tcl_AppendElement(interp, msg); - return; - } - - for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; - count > 0; tagPtr++, count--) { - if (tag == *tagPtr) { - return; - } - } - - /* - * Grow the tag space if there's no more room left in the current - * block. - */ - - if (itemPtr->tagSpace == itemPtr->numTags) { - Tk_Uid *newTagPtr; - - itemPtr->tagSpace += 5; - newTagPtr = (Tk_Uid *) ckalloc((unsigned) - (itemPtr->tagSpace * sizeof(Tk_Uid))); - memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr, - (itemPtr->numTags * sizeof(Tk_Uid))); - if (itemPtr->tagPtr != itemPtr->staticTagSpace) { - ckfree((char *) itemPtr->tagPtr); - } - itemPtr->tagPtr = newTagPtr; - tagPtr = &itemPtr->tagPtr[itemPtr->numTags]; - } - - /* - * Add in the new tag. - */ - - *tagPtr = tag; - itemPtr->numTags++; -} - -/* - *-------------------------------------------------------------- - * - * FindItems -- - * - * This procedure does all the work of implementing the - * "find" and "addtag" options of the canvas widget command, - * which locate items that have certain features (location, - * tags, position in display list, etc.). - * - * Results: - * A standard Tcl return value. If newTag is NULL, then a - * list of ids from all the items that match argc/argv is - * returned in interp->result. If newTag is NULL, then - * the normal interp->result is an empty string. If an error - * occurs, then interp->result will hold an error message. - * - * Side effects: - * If newTag is non-NULL, then all the items that match the - * information in argc/argv have that tag added to their - * lists of tags. - * - *-------------------------------------------------------------- - */ - -static int -FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - TkCanvas *canvasPtr; /* Canvas whose items are to be - * searched. */ - int argc; /* Number of entries in argv. Must be - * greater than zero. */ - char **argv; /* Arguments that describe what items - * to search for (see user doc on - * "find" and "addtag" options). */ - char *newTag; /* If non-NULL, gives new tag to set - * on all found items; if NULL, then - * ids of found items are returned - * in interp->result. */ - char *cmdName; /* Name of original Tcl command, for - * use in error messages. */ - char *option; /* For error messages: gives option - * from Tcl command and other stuff - * up to what's in argc/argv. */ -{ - int c; - size_t length; - TagSearch search; - Tk_Item *itemPtr; - Tk_Uid uid; - - if (newTag != NULL) { - uid = Tk_GetUid(newTag); - } else { - uid = NULL; - } - c = argv[0][0]; - length = strlen(argv[0]); - if ((c == 'a') && (strncmp(argv[0], "above", length) == 0) - && (length >= 2)) { - Tk_Item *lastPtr = NULL; - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " above tagOrId", (char *) NULL); - return TCL_ERROR; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - lastPtr = itemPtr; - } - if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) { - DoItem(interp, lastPtr->nextPtr, uid); - } - } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0) - && (length >= 2)) { - if (argc != 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " all", (char *) NULL); - return TCL_ERROR; - } - - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - DoItem(interp, itemPtr, uid); - } - } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " below tagOrId", (char *) NULL); - return TCL_ERROR; - } - (void) StartTagSearch(canvasPtr, argv[1], &search); - if (search.prevPtr != NULL) { - DoItem(interp, search.prevPtr, uid); - } - } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) { - double closestDist; - Tk_Item *startPtr, *closestPtr; - double coords[2], halo; - int x1, y1, x2, y2; - - if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " closest x y ?halo? ?start?", - (char *) NULL); - return TCL_ERROR; - } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], - &coords[0]) != TCL_OK) || (Tk_CanvasGetCoord(interp, - (Tk_Canvas) canvasPtr, argv[2], &coords[1]) != TCL_OK)) { - return TCL_ERROR; - } - if (argc > 3) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &halo) != TCL_OK) { - return TCL_ERROR; - } - if (halo < 0.0) { - Tcl_AppendResult(interp, "can't have negative halo value \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - } else { - halo = 0.0; - } - - /* - * Find the item at which to start the search. - */ - - startPtr = canvasPtr->firstItemPtr; - if (argc == 5) { - itemPtr = StartTagSearch(canvasPtr, argv[4], &search); - if (itemPtr != NULL) { - startPtr = itemPtr; - } - } - - /* - * The code below is optimized so that it can eliminate most - * items without having to call their item-specific procedures. - * This is done by keeping a bounding box (x1, y1, x2, y2) that - * an item's bbox must overlap if the item is to have any - * chance of being closer than the closest so far. - */ - - itemPtr = startPtr; - if (itemPtr == NULL) { - return TCL_OK; - } - closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr, - itemPtr, coords) - halo; - if (closestDist < 0.0) { - closestDist = 0.0; - } - while (1) { - double newDist; - - /* - * Update the bounding box using itemPtr, which is the - * new closest item. - */ - - x1 = (int) (coords[0] - closestDist - halo - 1); - y1 = (int) (coords[1] - closestDist - halo - 1); - x2 = (int) (coords[0] + closestDist + halo + 1); - y2 = (int) (coords[1] + closestDist + halo + 1); - closestPtr = itemPtr; - - /* - * Search for an item that beats the current closest one. - * Work circularly through the canvas's item list until - * getting back to the starting item. - */ - - while (1) { - itemPtr = itemPtr->nextPtr; - if (itemPtr == NULL) { - itemPtr = canvasPtr->firstItemPtr; - } - if (itemPtr == startPtr) { - DoItem(interp, closestPtr, uid); - return TCL_OK; - } - if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) - || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { - continue; - } - newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr, - itemPtr, coords) - halo; - if (newDist < 0.0) { - newDist = 0.0; - } - if (newDist <= closestDist) { - closestDist = newDist; - break; - } - } - } - } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL); - return TCL_ERROR; - } - return FindArea(interp, canvasPtr, argv+1, uid, 1); - } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " overlapping x1 y1 x2 y2", - (char *) NULL); - return TCL_ERROR; - } - return FindArea(interp, canvasPtr, argv+1, uid, 0); - } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " withtag tagOrId", (char *) NULL); - return TCL_ERROR; - } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - DoItem(interp, itemPtr, uid); - } - } else { - Tcl_AppendResult(interp, "bad search command \"", argv[0], - "\": must be above, all, below, closest, enclosed, ", - "overlapping, or withtag", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * FindArea -- - * - * This procedure implements area searches for the "find" - * and "addtag" options. - * - * Results: - * A standard Tcl return value. If newTag is NULL, then a - * list of ids from all the items overlapping or enclosed - * by the rectangle given by argc is returned in interp->result. - * If newTag is NULL, then the normal interp->result is an - * empty string. If an error occurs, then interp->result will - * hold an error message. - * - * Side effects: - * If uid is non-NULL, then all the items overlapping - * or enclosed by the area in argv have that tag added to - * their lists of tags. - * - *-------------------------------------------------------------- - */ - -static int -FindArea(interp, canvasPtr, argv, uid, enclosed) - Tcl_Interp *interp; /* Interpreter for error reporting - * and result storing. */ - TkCanvas *canvasPtr; /* Canvas whose items are to be - * searched. */ - char **argv; /* Array of four arguments that - * give the coordinates of the - * rectangular area to search. */ - Tk_Uid uid; /* If non-NULL, gives new tag to set - * on all found items; if NULL, then - * ids of found items are returned - * in interp->result. */ - int enclosed; /* 0 means overlapping or enclosed - * items are OK, 1 means only enclosed - * items are OK. */ -{ - double rect[4], tmp; - int x1, y1, x2, y2; - Tk_Item *itemPtr; - - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0], - &rect[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], - &rect[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2], - &rect[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &rect[3]) != TCL_OK)) { - return TCL_ERROR; - } - if (rect[0] > rect[2]) { - tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp; - } - if (rect[1] > rect[3]) { - tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp; - } - - /* - * Use an integer bounding box for a quick test, to avoid - * calling item-specific code except for items that are close. - */ - - x1 = (int) (rect[0]-1.0); - y1 = (int) (rect[1]-1.0); - x2 = (int) (rect[2]+1.0); - y2 = (int) (rect[3]+1.0); - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) - || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { - continue; - } - if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect) - >= enclosed) { - DoItem(interp, itemPtr, uid); - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * RelinkItems -- - * - * Move one or more items to a different place in the - * display order for a canvas. - * - * Results: - * None. - * - * Side effects: - * The items identified by "tag" are moved so that they - * are all together in the display list and immediately - * after prevPtr. The order of the moved items relative - * to each other is not changed. - * - *-------------------------------------------------------------- - */ - -static void -RelinkItems(canvasPtr, tag, prevPtr) - TkCanvas *canvasPtr; /* Canvas to be modified. */ - char *tag; /* Tag identifying items to be moved - * in the redisplay list. */ - Tk_Item *prevPtr; /* Reposition the items so that they - * go just after this item (NULL means - * put at beginning of list). */ -{ - Tk_Item *itemPtr; - TagSearch search; - Tk_Item *firstMovePtr, *lastMovePtr; - - /* - * Find all of the items to be moved and remove them from - * the list, making an auxiliary list running from firstMovePtr - * to lastMovePtr. Record their areas for redisplay. - */ - - firstMovePtr = lastMovePtr = NULL; - for (itemPtr = StartTagSearch(canvasPtr, tag, &search); - itemPtr != NULL; itemPtr = NextItem(&search)) { - if (itemPtr == prevPtr) { - /* - * Item after which insertion is to occur is being - * moved! Switch to insert after its predecessor. - */ - - prevPtr = search.prevPtr; - } - if (search.prevPtr == NULL) { - canvasPtr->firstItemPtr = itemPtr->nextPtr; - } else { - search.prevPtr->nextPtr = itemPtr->nextPtr; - } - if (canvasPtr->lastItemPtr == itemPtr) { - canvasPtr->lastItemPtr = search.prevPtr; - } - if (firstMovePtr == NULL) { - firstMovePtr = itemPtr; - } else { - lastMovePtr->nextPtr = itemPtr; - } - lastMovePtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1, - itemPtr->x2, itemPtr->y2); - canvasPtr->flags |= REPICK_NEEDED; - } - - /* - * Insert the list of to-be-moved items back into the canvas's - * at the desired position. - */ - - if (firstMovePtr == NULL) { - return; - } - if (prevPtr == NULL) { - lastMovePtr->nextPtr = canvasPtr->firstItemPtr; - canvasPtr->firstItemPtr = firstMovePtr; - } else { - lastMovePtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = firstMovePtr; - } - if (canvasPtr->lastItemPtr == prevPtr) { - canvasPtr->lastItemPtr = lastMovePtr; - } -} - -/* - *-------------------------------------------------------------- - * - * CanvasBindProc -- - * - * This procedure is invoked by the Tk dispatcher to handle - * events associated with bindings on items. - * - * Results: - * None. - * - * Side effects: - * Depends on the command invoked as part of the binding - * (if there was any). - * - *-------------------------------------------------------------- - */ - -static void -CanvasBindProc(clientData, eventPtr) - ClientData clientData; /* Pointer to canvas structure. */ - XEvent *eventPtr; /* Pointer to X event that just - * happened. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - - Tcl_Preserve((ClientData) canvasPtr); - - /* - * This code below keeps track of the current modifier state in - * canvasPtr>state. This information is used to defer repicks of - * the current item while buttons are down. - */ - - if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) { - int mask; - - switch (eventPtr->xbutton.button) { - case Button1: - mask = Button1Mask; - break; - case Button2: - mask = Button2Mask; - break; - case Button3: - mask = Button3Mask; - break; - case Button4: - mask = Button4Mask; - break; - case Button5: - mask = Button5Mask; - break; - default: - mask = 0; - break; - } - - /* - * For button press events, repick the current item using the - * button state before the event, then process the event. For - * button release events, first process the event, then repick - * the current item using the button state *after* the event - * (the button has logically gone up before we change the - * current item). - */ - - if (eventPtr->type == ButtonPress) { - /* - * On a button press, first repick the current item using - * the button state before the event, the process the event. - */ - - canvasPtr->state = eventPtr->xbutton.state; - PickCurrentItem(canvasPtr, eventPtr); - canvasPtr->state ^= mask; - CanvasDoEvent(canvasPtr, eventPtr); - } else { - /* - * Button release: first process the event, with the button - * still considered to be down. Then repick the current - * item under the assumption that the button is no longer down. - */ - - canvasPtr->state = eventPtr->xbutton.state; - CanvasDoEvent(canvasPtr, eventPtr); - eventPtr->xbutton.state ^= mask; - canvasPtr->state = eventPtr->xbutton.state; - PickCurrentItem(canvasPtr, eventPtr); - eventPtr->xbutton.state ^= mask; - } - goto done; - } else if ((eventPtr->type == EnterNotify) - || (eventPtr->type == LeaveNotify)) { - canvasPtr->state = eventPtr->xcrossing.state; - PickCurrentItem(canvasPtr, eventPtr); - goto done; - } else if (eventPtr->type == MotionNotify) { - canvasPtr->state = eventPtr->xmotion.state; - PickCurrentItem(canvasPtr, eventPtr); - } - CanvasDoEvent(canvasPtr, eventPtr); - - done: - Tcl_Release((ClientData) canvasPtr); -} - -/* - *-------------------------------------------------------------- - * - * PickCurrentItem -- - * - * Find the topmost item in a canvas that contains a given - * location and mark the the current item. If the current - * item has changed, generate a fake exit event on the old - * current item and a fake enter event on the new current - * item. - * - * Results: - * None. - * - * Side effects: - * The current item for canvasPtr may change. If it does, - * then the commands associated with item entry and exit - * could do just about anything. A binding script could - * delete the canvas, so callers should protect themselves - * with Tcl_Preserve and Tcl_Release. - * - *-------------------------------------------------------------- - */ - -static void -PickCurrentItem(canvasPtr, eventPtr) - TkCanvas *canvasPtr; /* Canvas widget in which to select - * current item. */ - XEvent *eventPtr; /* Event describing location of - * mouse cursor. Must be EnterWindow, - * LeaveWindow, ButtonRelease, or - * MotionNotify. */ -{ - double coords[2]; - int buttonDown; - - /* - * Check whether or not a button is down. If so, we'll log entry - * and exit into and out of the current item, but not entry into - * any other item. This implements a form of grabbing equivalent - * to what the X server does for windows. - */ - - buttonDown = canvasPtr->state - & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); - if (!buttonDown) { - canvasPtr->flags &= ~LEFT_GRABBED_ITEM; - } - - /* - * Save information about this event in the canvas. The event in - * the canvas is used for two purposes: - * - * 1. Event bindings: if the current item changes, fake events are - * generated to allow item-enter and item-leave bindings to trigger. - * 2. Reselection: if the current item gets deleted, can use the - * saved event to find a new current item. - * Translate MotionNotify events into EnterNotify events, since that's - * what gets reported to item handlers. - */ - - if (eventPtr != &canvasPtr->pickEvent) { - if ((eventPtr->type == MotionNotify) - || (eventPtr->type == ButtonRelease)) { - canvasPtr->pickEvent.xcrossing.type = EnterNotify; - canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial; - canvasPtr->pickEvent.xcrossing.send_event - = eventPtr->xmotion.send_event; - canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display; - canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window; - canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root; - canvasPtr->pickEvent.xcrossing.subwindow = None; - canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time; - canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x; - canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y; - canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root; - canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root; - canvasPtr->pickEvent.xcrossing.mode = NotifyNormal; - canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear; - canvasPtr->pickEvent.xcrossing.same_screen - = eventPtr->xmotion.same_screen; - canvasPtr->pickEvent.xcrossing.focus = False; - canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state; - } else { - canvasPtr->pickEvent = *eventPtr; - } - } - - /* - * If this is a recursive call (there's already a partially completed - * call pending on the stack; it's in the middle of processing a - * Leave event handler for the old current item) then just return; - * the pending call will do everything that's needed. - */ - - if (canvasPtr->flags & REPICK_IN_PROGRESS) { - return; - } - - /* - * A LeaveNotify event automatically means that there's no current - * object, so the check for closest item can be skipped. - */ - - coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin; - coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin; - if (canvasPtr->pickEvent.type != LeaveNotify) { - canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords); - } else { - canvasPtr->newCurrentPtr = NULL; - } - - if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr) - && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) { - /* - * Nothing to do: the current item hasn't changed. - */ - - return; - } - - /* - * Simulate a LeaveNotify event on the previous current item and - * an EnterNotify event on the new current item. Remove the "current" - * tag from the previous current item and place it on the new current - * item. - */ - - if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) - && (canvasPtr->currentItemPtr != NULL) - && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) { - XEvent event; - Tk_Item *itemPtr = canvasPtr->currentItemPtr; - int i; - - event = canvasPtr->pickEvent; - event.type = LeaveNotify; - - /* - * If the event's detail happens to be NotifyInferior the - * binding mechanism will discard the event. To be consistent, - * always use NotifyAncestor. - */ - - event.xcrossing.detail = NotifyAncestor; - canvasPtr->flags |= REPICK_IN_PROGRESS; - CanvasDoEvent(canvasPtr, &event); - canvasPtr->flags &= ~REPICK_IN_PROGRESS; - - /* - * The check below is needed because there could be an event - * handler for <LeaveNotify> that deletes the current item. - */ - - if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) { - for (i = itemPtr->numTags-1; i >= 0; i--) { - if (itemPtr->tagPtr[i] == currentUid) { - itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; - itemPtr->numTags--; - break; - } - } - } - - /* - * Note: during CanvasDoEvent above, it's possible that - * canvasPtr->newCurrentPtr got reset to NULL because the - * item was deleted. - */ - } - if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) { - canvasPtr->flags |= LEFT_GRABBED_ITEM; - return; - } - - /* - * Special note: it's possible that canvasPtr->newCurrentPtr == - * canvasPtr->currentItemPtr here. This can happen, for example, - * if LEFT_GRABBED_ITEM was set. - */ - - canvasPtr->flags &= ~LEFT_GRABBED_ITEM; - canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr; - if (canvasPtr->currentItemPtr != NULL) { - XEvent event; - - DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid); - event = canvasPtr->pickEvent; - event.type = EnterNotify; - event.xcrossing.detail = NotifyAncestor; - CanvasDoEvent(canvasPtr, &event); - } -} - -/* - *---------------------------------------------------------------------- - * - * CanvasFindClosest -- - * - * Given x and y coordinates, find the topmost canvas item that - * is "close" to the coordinates. - * - * Results: - * The return value is a pointer to the topmost item that is - * close to (x,y), or NULL if no item is close. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Tk_Item * -CanvasFindClosest(canvasPtr, coords) - TkCanvas *canvasPtr; /* Canvas widget to search. */ - double coords[2]; /* Desired x,y position in canvas, - * not screen, coordinates.) */ -{ - Tk_Item *itemPtr; - Tk_Item *bestPtr; - int x1, y1, x2, y2; - - x1 = (int) (coords[0] - canvasPtr->closeEnough); - y1 = (int) (coords[1] - canvasPtr->closeEnough); - x2 = (int) (coords[0] + canvasPtr->closeEnough); - y2 = (int) (coords[1] + canvasPtr->closeEnough); - - bestPtr = NULL; - for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; - itemPtr = itemPtr->nextPtr) { - if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1) - || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) { - continue; - } - if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr, - itemPtr, coords) <= canvasPtr->closeEnough) { - bestPtr = itemPtr; - } - } - return bestPtr; -} - -/* - *-------------------------------------------------------------- - * - * CanvasDoEvent -- - * - * This procedure is called to invoke binding processing - * for a new event that is associated with the current item - * for a canvas. - * - * Results: - * None. - * - * Side effects: - * Depends on the bindings for the canvas. A binding script - * could delete the canvas, so callers should protect themselves - * with Tcl_Preserve and Tcl_Release. - * - *-------------------------------------------------------------- - */ - -static void -CanvasDoEvent(canvasPtr, eventPtr) - TkCanvas *canvasPtr; /* Canvas widget in which event - * occurred. */ - XEvent *eventPtr; /* Real or simulated X event that - * is to be processed. */ -{ -#define NUM_STATIC 3 - ClientData staticObjects[NUM_STATIC]; - ClientData *objectPtr; - int numObjects, i; - Tk_Item *itemPtr; - - if (canvasPtr->bindingTable == NULL) { - return; - } - - itemPtr = canvasPtr->currentItemPtr; - if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) { - itemPtr = canvasPtr->textInfo.focusItemPtr; - } - if (itemPtr == NULL) { - return; - } - - /* - * Set up an array with all the relevant objects for processing - * this event. The relevant objects are (a) the event's item, - * (b) the tags associated with the event's item, and (c) the - * tag "all". If there are a lot of tags then malloc an array - * to hold all of the objects. - */ - - numObjects = itemPtr->numTags + 2; - if (numObjects <= NUM_STATIC) { - objectPtr = staticObjects; - } else { - objectPtr = (ClientData *) ckalloc((unsigned) - (numObjects * sizeof(ClientData))); - } - objectPtr[0] = (ClientData) allUid; - for (i = itemPtr->numTags-1; i >= 0; i--) { - objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i]; - } - objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr; - - /* - * Invoke the binding system, then free up the object array if - * it was malloc-ed. - */ - - if (canvasPtr->tkwin != NULL) { - Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin, - numObjects, objectPtr); - } - if (objectPtr != staticObjects) { - ckfree((char *) objectPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * CanvasBlinkProc -- - * - * This procedure is called as a timer handler to blink the - * insertion cursor off and on. - * - * Results: - * None. - * - * Side effects: - * The cursor gets turned on or off, redisplay gets invoked, - * and this procedure reschedules itself. - * - *---------------------------------------------------------------------- - */ - -static void -CanvasBlinkProc(clientData) - ClientData clientData; /* Pointer to record describing entry. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - - if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) { - return; - } - if (canvasPtr->textInfo.cursorOn) { - canvasPtr->textInfo.cursorOn = 0; - canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - canvasPtr->insertOffTime, CanvasBlinkProc, - (ClientData) canvasPtr); - } else { - canvasPtr->textInfo.cursorOn = 1; - canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - canvasPtr->insertOnTime, CanvasBlinkProc, - (ClientData) canvasPtr); - } - if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); - } -} - -/* - *---------------------------------------------------------------------- - * - * CanvasFocusProc -- - * - * This procedure is called whenever a canvas gets or loses the - * input focus. It's also called whenever the window is - * reconfigured while it has the focus. - * - * Results: - * None. - * - * Side effects: - * The cursor gets turned on or off. - * - *---------------------------------------------------------------------- - */ - -static void -CanvasFocusProc(canvasPtr, gotFocus) - TkCanvas *canvasPtr; /* Canvas that just got or lost focus. */ - int gotFocus; /* 1 means window is getting focus, 0 means - * it's losing it. */ -{ - Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); - if (gotFocus) { - canvasPtr->textInfo.gotFocus = 1; - canvasPtr->textInfo.cursorOn = 1; - if (canvasPtr->insertOffTime != 0) { - canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - canvasPtr->insertOffTime, CanvasBlinkProc, - (ClientData) canvasPtr); - } - } else { - canvasPtr->textInfo.gotFocus = 0; - canvasPtr->textInfo.cursorOn = 0; - canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - } - if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); - } - if (canvasPtr->highlightWidth > 0) { - canvasPtr->flags |= REDRAW_BORDERS; - if (!(canvasPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); - canvasPtr->flags |= REDRAW_PENDING; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * CanvasSelectTo -- - * - * Modify the selection by moving its un-anchored end. This could - * make the selection either larger or smaller. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - *---------------------------------------------------------------------- - */ - -static void -CanvasSelectTo(canvasPtr, itemPtr, index) - TkCanvas *canvasPtr; /* Information about widget. */ - Tk_Item *itemPtr; /* Item that is to hold selection. */ - int index; /* Index of element that is to become the - * "other" end of the selection. */ -{ - int oldFirst, oldLast; - Tk_Item *oldSelPtr; - - oldFirst = canvasPtr->textInfo.selectFirst; - oldLast = canvasPtr->textInfo.selectLast; - oldSelPtr = canvasPtr->textInfo.selItemPtr; - - /* - * Grab the selection if we don't own it already. - */ - - if (canvasPtr->textInfo.selItemPtr == NULL) { - Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection, - (ClientData) canvasPtr); - } else if (canvasPtr->textInfo.selItemPtr != itemPtr) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); - } - canvasPtr->textInfo.selItemPtr = itemPtr; - - if (canvasPtr->textInfo.anchorItemPtr != itemPtr) { - canvasPtr->textInfo.anchorItemPtr = itemPtr; - canvasPtr->textInfo.selectAnchor = index; - } - if (canvasPtr->textInfo.selectAnchor <= index) { - canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor; - canvasPtr->textInfo.selectLast = index; - } else { - canvasPtr->textInfo.selectFirst = index; - canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1; - } - if ((canvasPtr->textInfo.selectFirst != oldFirst) - || (canvasPtr->textInfo.selectLast != oldLast) - || (itemPtr != oldSelPtr)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - } -} - -/* - *-------------------------------------------------------------- - * - * CanvasFetchSelection -- - * - * This procedure is invoked by Tk to return part or all of - * the selection, when the selection is in a canvas widget. - * This procedure always returns the selection as a STRING. - * - * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -CanvasFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about canvas widget. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - - if (canvasPtr->textInfo.selItemPtr == NULL) { - return -1; - } - if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) { - return -1; - } - return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)( - (Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset, - buffer, maxBytes); -} - -/* - *---------------------------------------------------------------------- - * - * CanvasLostSelection -- - * - * This procedure is called back by Tk when the selection is - * grabbed away from a canvas widget. - * - * Results: - * None. - * - * Side effects: - * The existing selection is unhighlighted, and the window is - * marked as not containing a selection. - * - *---------------------------------------------------------------------- - */ - -static void -CanvasLostSelection(clientData) - ClientData clientData; /* Information about entry widget. */ -{ - TkCanvas *canvasPtr = (TkCanvas *) clientData; - - if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); - } - canvasPtr->textInfo.selItemPtr = NULL; -} - -/* - *-------------------------------------------------------------- - * - * GridAlign -- - * - * Given a coordinate and a grid spacing, this procedure - * computes the location of the nearest grid line to the - * coordinate. - * - * Results: - * The return value is the location of the grid line nearest - * to coord. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static double -GridAlign(coord, spacing) - double coord; /* Coordinate to grid-align. */ - double spacing; /* Spacing between grid lines. If <= 0 - * then no alignment is done. */ -{ - if (spacing <= 0.0) { - return coord; - } - if (coord < 0) { - return -((int) ((-coord)/spacing + 0.5)) * spacing; - } - return ((int) (coord/spacing + 0.5)) * spacing; -} - -/* - *---------------------------------------------------------------------- - * - * PrintScrollFractions -- - * - * Given the range that's visible in the window and the "100% - * range" for what's in the canvas, print a string containing - * the scroll fractions. This procedure is used for both x - * and y scrolling. - * - * Results: - * The memory pointed to by string is modified to hold - * two real numbers containing the scroll fractions (between - * 0 and 1) corresponding to the other arguments. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -PrintScrollFractions(screen1, screen2, object1, object2, string) - int screen1; /* Lowest coordinate visible in the window. */ - int screen2; /* Highest coordinate visible in the window. */ - int object1; /* Lowest coordinate in the object. */ - int object2; /* Highest coordinate in the object. */ - char *string; /* Two real numbers get printed here. Must - * have enough storage for two %g - * conversions. */ -{ - double range, f1, f2; - - range = object2 - object1; - if (range <= 0) { - f1 = 0; - f2 = 1.0; - } else { - f1 = (screen1 - object1)/range; - if (f1 < 0) { - f1 = 0.0; - } - f2 = (screen2 - object1)/range; - if (f2 > 1.0) { - f2 = 1.0; - } - if (f2 < f1) { - f2 = f1; - } - } - sprintf(string, "%g %g", f1, f2); -} - -/* - *-------------------------------------------------------------- - * - * CanvasUpdateScrollbars -- - * - * This procedure is invoked whenever a canvas has changed in - * a way that requires scrollbars to be redisplayed (e.g. the - * view in the canvas has changed). - * - * Results: - * None. - * - * Side effects: - * If there are scrollbars associated with the canvas, then - * their scrolling commands are invoked to cause them to - * redisplay. If errors occur, additional Tcl commands may - * be invoked to process the errors. - * - *-------------------------------------------------------------- - */ - -static void -CanvasUpdateScrollbars(canvasPtr) - TkCanvas *canvasPtr; /* Information about canvas. */ -{ - int result; - char buffer[200]; - Tcl_Interp *interp; - int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2, - scrollY1, scrollY2; - char *xScrollCmd, *yScrollCmd; - - /* - * Save all the relevant values from the canvasPtr, because it might be - * deleted as part of either of the two calls to Tcl_VarEval below. - */ - - interp = canvasPtr->interp; - Tcl_Preserve((ClientData) interp); - xScrollCmd = canvasPtr->xScrollCmd; - if (xScrollCmd != (char *) NULL) { - Tcl_Preserve((ClientData) xScrollCmd); - } - yScrollCmd = canvasPtr->yScrollCmd; - if (yScrollCmd != (char *) NULL) { - Tcl_Preserve((ClientData) yScrollCmd); - } - xOrigin = canvasPtr->xOrigin; - yOrigin = canvasPtr->yOrigin; - inset = canvasPtr->inset; - width = Tk_Width(canvasPtr->tkwin); - height = Tk_Height(canvasPtr->tkwin); - scrollX1 = canvasPtr->scrollX1; - scrollX2 = canvasPtr->scrollX2; - scrollY1 = canvasPtr->scrollY1; - scrollY2 = canvasPtr->scrollY2; - canvasPtr->flags &= ~UPDATE_SCROLLBARS; - if (canvasPtr->xScrollCmd != NULL) { - PrintScrollFractions(xOrigin + inset, xOrigin + width - inset, - scrollX1, scrollX2, buffer); - result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL); - if (result != TCL_OK) { - Tcl_BackgroundError(interp); - } - Tcl_ResetResult(interp); - Tcl_Release((ClientData) xScrollCmd); - } - - if (yScrollCmd != NULL) { - PrintScrollFractions(yOrigin + inset, yOrigin + height - inset, - scrollY1, scrollY2, buffer); - result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL); - if (result != TCL_OK) { - Tcl_BackgroundError(interp); - } - Tcl_ResetResult(interp); - Tcl_Release((ClientData) yScrollCmd); - } - Tcl_Release((ClientData) interp); -} - -/* - *-------------------------------------------------------------- - * - * CanvasSetOrigin -- - * - * This procedure is invoked to change the mapping between - * canvas coordinates and screen coordinates in the canvas - * window. - * - * Results: - * None. - * - * Side effects: - * The canvas will be redisplayed to reflect the change in - * view. In addition, scrollbars will be updated if there - * are any. - * - *-------------------------------------------------------------- - */ - -static void -CanvasSetOrigin(canvasPtr, xOrigin, yOrigin) - TkCanvas *canvasPtr; /* Information about canvas. */ - int xOrigin; /* New X origin for canvas (canvas x-coord - * corresponding to left edge of canvas - * window). */ - int yOrigin; /* New Y origin for canvas (canvas y-coord - * corresponding to top edge of canvas - * window). */ -{ - int left, right, top, bottom, delta; - - /* - * If scroll increments have been set, round the window origin - * to the nearest multiple of the increments. Remember, the - * origin is the place just inside the borders, not the upper - * left corner. - */ - - if (canvasPtr->xScrollIncrement > 0) { - if (xOrigin >= 0) { - xOrigin += canvasPtr->xScrollIncrement/2; - xOrigin -= (xOrigin + canvasPtr->inset) - % canvasPtr->xScrollIncrement; - } else { - xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2; - xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset) - % canvasPtr->xScrollIncrement); - } - } - if (canvasPtr->yScrollIncrement > 0) { - if (yOrigin >= 0) { - yOrigin += canvasPtr->yScrollIncrement/2; - yOrigin -= (yOrigin + canvasPtr->inset) - % canvasPtr->yScrollIncrement; - } else { - yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2; - yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset) - % canvasPtr->yScrollIncrement); - } - } - - /* - * Adjust the origin if necessary to keep as much as possible of the - * canvas in the view. The variables left, right, etc. keep track of - * how much extra space there is on each side of the view before it - * will stick out past the scroll region. If one side sticks out past - * the edge of the scroll region, adjust the view to bring that side - * back to the edge of the scrollregion (but don't move it so much that - * the other side sticks out now). If scroll increments are in effect, - * be sure to adjust only by full increments. - */ - - if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) { - left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1; - right = canvasPtr->scrollX2 - - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset); - top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1; - bottom = canvasPtr->scrollY2 - - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset); - if ((left < 0) && (right > 0)) { - delta = (right > -left) ? -left : right; - if (canvasPtr->xScrollIncrement > 0) { - delta -= delta % canvasPtr->xScrollIncrement; - } - xOrigin += delta; - } else if ((right < 0) && (left > 0)) { - delta = (left > -right) ? -right : left; - if (canvasPtr->xScrollIncrement > 0) { - delta -= delta % canvasPtr->xScrollIncrement; - } - xOrigin -= delta; - } - if ((top < 0) && (bottom > 0)) { - delta = (bottom > -top) ? -top : bottom; - if (canvasPtr->yScrollIncrement > 0) { - delta -= delta % canvasPtr->yScrollIncrement; - } - yOrigin += delta; - } else if ((bottom < 0) && (top > 0)) { - delta = (top > -bottom) ? -bottom : top; - if (canvasPtr->yScrollIncrement > 0) { - delta -= delta % canvasPtr->yScrollIncrement; - } - yOrigin -= delta; - } - } - - if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) { - return; - } - - /* - * Tricky point: must redisplay not only everything that's visible - * in the window's final configuration, but also everything that was - * visible in the initial configuration. This is needed because some - * item types, like windows, need to know when they move off-screen - * so they can explicitly undisplay themselves. - */ - - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->xOrigin, canvasPtr->yOrigin, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); - canvasPtr->xOrigin = xOrigin; - canvasPtr->yOrigin = yOrigin; - canvasPtr->flags |= UPDATE_SCROLLBARS; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->xOrigin, canvasPtr->yOrigin, - canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), - canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); -} diff --git a/generic/tkCanvas.h b/generic/tkCanvas.h deleted file mode 100644 index a96fa6b..0000000 --- a/generic/tkCanvas.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * tkCanvas.h -- - * - * Declarations shared among all the files that implement - * canvas widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCanvas.h,v 1.2 1998/09/14 18:23:07 stanton Exp $ - */ - -#ifndef _TKCANVAS -#define _TKCANVAS - -#ifndef _TK -#include "tk.h" -#endif - -/* - * The record below describes a canvas widget. It is made available - * to the item procedures so they can access certain shared fields such - * as the overall displacement and scale factor for the canvas. - */ - -typedef struct TkCanvas { - Tk_Window tkwin; /* Window that embodies the canvas. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget; needed, among - * other things, to release resources after - * tkwin has already gone away. */ - Tcl_Interp *interp; /* Interpreter associated with canvas. */ - Tcl_Command widgetCmd; /* Token for canvas's widget command. */ - Tk_Item *firstItemPtr; /* First in list of all items in canvas, - * or NULL if canvas empty. */ - Tk_Item *lastItemPtr; /* Last in list of all items in canvas, - * or NULL if canvas empty. */ - - /* - * Information used when displaying widget: - */ - - int borderWidth; /* Width of 3-D border around window. */ - Tk_3DBorder bgBorder; /* Used for canvas background. */ - int relief; /* Indicates whether window as a whole is - * raised, sunken, or flat. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - GC pixmapGC; /* Used to copy bits from a pixmap to the - * screen and also to clear the pixmap. */ - int width, height; /* Dimensions to request for canvas window, - * specified in pixels. */ - int redrawX1, redrawY1; /* Upper left corner of area to redraw, - * in pixel coordinates. Border pixels - * are included. Only valid if - * REDRAW_PENDING flag is set. */ - int redrawX2, redrawY2; /* Lower right corner of area to redraw, - * in integer canvas coordinates. Border - * pixels will *not* be redrawn. */ - int confine; /* Non-zero means constrain view to keep - * as much of canvas visible as possible. */ - - /* - * Information used to manage the selection and insertion cursor: - */ - - Tk_CanvasTextInfo textInfo; /* Contains lots of fields; see tk.h for - * details. This structure is shared with - * the code that implements individual items. */ - int insertOnTime; /* Number of milliseconds cursor should spend - * in "on" state for each blink. */ - int insertOffTime; /* Number of milliseconds cursor should spend - * in "off" state for each blink. */ - Tcl_TimerToken insertBlinkHandler; - /* Timer handler used to blink cursor on and - * off. */ - - /* - * Transformation applied to canvas as a whole: to compute screen - * coordinates (X,Y) from canvas coordinates (x,y), do the following: - * - * X = x - xOrigin; - * Y = y - yOrigin; - */ - - int xOrigin, yOrigin; /* Canvas coordinates corresponding to - * upper-left corner of window, given in - * canvas pixel units. */ - int drawableXOrigin, drawableYOrigin; - /* During redisplay, these fields give the - * canvas coordinates corresponding to - * the upper-left corner of the drawable - * where items are actually being drawn - * (typically a pixmap smaller than the - * whole window). */ - - /* - * Information used for event bindings associated with items. - */ - - Tk_BindingTable bindingTable; - /* Table of all bindings currently defined - * for this canvas. NULL means that no - * bindings exist, so the table hasn't been - * created. Each "object" used for this - * table is either a Tk_Uid for a tag or - * the address of an item named by id. */ - Tk_Item *currentItemPtr; /* The item currently containing the mouse - * pointer, or NULL if none. */ - Tk_Item *newCurrentPtr; /* The item that is about to become the - * current one, or NULL. This field is - * used to detect deletions of the new - * current item pointer that occur during - * Leave processing of the previous current - * item. */ - double closeEnough; /* The mouse is assumed to be inside an - * item if it is this close to it. */ - XEvent pickEvent; /* The event upon which the current choice - * of currentItem is based. Must be saved - * so that if the currentItem is deleted, - * can pick another. */ - int state; /* Last known modifier state. Used to - * defer picking a new current object - * while buttons are down. */ - - /* - * Information used for managing scrollbars: - */ - - char *xScrollCmd; /* Command prefix for communicating with - * horizontal scrollbar. NULL means no - * horizontal scrollbar. Malloc'ed*/ - char *yScrollCmd; /* Command prefix for communicating with - * vertical scrollbar. NULL means no - * vertical scrollbar. Malloc'ed*/ - int scrollX1, scrollY1, scrollX2, scrollY2; - /* These four coordinates define the region - * that is the 100% area for scrolling (i.e. - * these numbers determine the size and - * location of the sliders on scrollbars). - * Units are pixels in canvas coords. */ - char *regionString; /* The option string from which scrollX1 - * etc. are derived. Malloc'ed. */ - int xScrollIncrement; /* If >0, defines a grid for horizontal - * scrolling. This is the size of the "unit", - * and the left edge of the screen will always - * lie on an even unit boundary. */ - int yScrollIncrement; /* If >0, defines a grid for horizontal - * scrolling. This is the size of the "unit", - * and the left edge of the screen will always - * lie on an even unit boundary. */ - - /* - * Information used for scanning: - */ - - int scanX; /* X-position at which scan started (e.g. - * button was pressed here). */ - int scanXOrigin; /* Value of xOrigin field when scan started. */ - int scanY; /* Y-position at which scan started (e.g. - * button was pressed here). */ - int scanYOrigin; /* Value of yOrigin field when scan started. */ - - /* - * Information used to speed up searches by remembering the last item - * created or found with an item id search. - */ - - Tk_Item *hotPtr; /* Pointer to "hot" item (one that's been - * recently used. NULL means there's no - * hot item. */ - Tk_Item *hotPrevPtr; /* Pointer to predecessor to hotPtr (NULL - * means item is first in list). This is - * only a hint and may not really be hotPtr's - * predecessor. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - double pixelsPerMM; /* Scale factor between MM and pixels; - * used when converting coordinates. */ - int flags; /* Various flags; see below for - * definitions. */ - int nextId; /* Number to use as id for next item - * created in widget. */ - struct TkPostscriptInfo *psInfoPtr; - /* Pointer to information used for generating - * Postscript for the canvas. NULL means - * no Postscript is currently being - * generated. */ -} TkCanvas; - -/* - * Flag bits for canvases: - * - * REDRAW_PENDING - 1 means a DoWhenIdle handler has already - * been created to redraw some or all of the - * canvas. - * REDRAW_BORDERS - 1 means that the borders need to be redrawn - * during the next redisplay operation. - * REPICK_NEEDED - 1 means DisplayCanvas should pick a new - * current item before redrawing the canvas. - * GOT_FOCUS - 1 means the focus is currently in this - * widget, so should draw the insertion cursor - * and traversal highlight. - * CURSOR_ON - 1 means the insertion cursor is in the "on" - * phase of its blink cycle. 0 means either - * we don't have the focus or the cursor is in - * the "off" phase of its cycle. - * UPDATE_SCROLLBARS - 1 means the scrollbars should get updated - * as part of the next display operation. - * LEFT_GRABBED_ITEM - 1 means that the mouse left the current - * item while a grab was in effect, so we - * didn't change canvasPtr->currentItemPtr. - * REPICK_IN_PROGRESS - 1 means PickCurrentItem is currently - * executing. If it should be called recursively, - * it should simply return immediately. - */ - -#define REDRAW_PENDING 1 -#define REDRAW_BORDERS 2 -#define REPICK_NEEDED 4 -#define GOT_FOCUS 8 -#define CURSOR_ON 0x10 -#define UPDATE_SCROLLBARS 0x20 -#define LEFT_GRABBED_ITEM 0x40 -#define REPICK_IN_PROGRESS 0x100 - -/* - * Canvas-related procedures that are shared among Tk modules but not - * exported to the outside world: - */ - -extern int TkCanvPostscriptCmd _ANSI_ARGS_((TkCanvas *canvasPtr, - Tcl_Interp *interp, int argc, char **argv)); - -#endif /* _TKCANVAS */ diff --git a/generic/tkClipboard.c b/generic/tkClipboard.c deleted file mode 100644 index 7df518a..0000000 --- a/generic/tkClipboard.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * tkClipboard.c -- - * - * This file manages the clipboard for the Tk toolkit, - * maintaining a collection of data buffers that will be - * supplied on demand to requesting applications. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkClipboard.c,v 1.2 1998/09/14 18:23:07 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" -#include "tkSelect.h" - -/* - * Prototypes for procedures used only in this file: - */ - -static int ClipboardAppHandler _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static int ClipboardHandler _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static int ClipboardWindowHandler _ANSI_ARGS_(( - ClientData clientData, int offset, char *buffer, - int maxBytes)); -static void ClipboardLostSel _ANSI_ARGS_((ClientData clientData)); - -/* - *---------------------------------------------------------------------- - * - * ClipboardHandler -- - * - * This procedure acts as selection handler for the - * clipboard manager. It extracts the required chunk of - * data from the buffer chain for a given selection target. - * - * Results: - * The return value is a count of the number of bytes - * actually stored at buffer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ClipboardHandler(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about data to fetch. */ - int offset; /* Return selection bytes starting at this - * offset. */ - char *buffer; /* Place to store converted selection. */ - int maxBytes; /* Maximum # of bytes to store at buffer. */ -{ - TkClipboardTarget *targetPtr = (TkClipboardTarget*) clientData; - TkClipboardBuffer *cbPtr; - char *srcPtr, *destPtr; - int count = 0; - int scanned = 0; - size_t length, freeCount; - - /* - * Skip to buffer containing offset byte - */ - - for (cbPtr = targetPtr->firstBufferPtr; ; cbPtr = cbPtr->nextPtr) { - if (cbPtr == NULL) { - return 0; - } - if (scanned + cbPtr->length > offset) { - break; - } - scanned += cbPtr->length; - } - - /* - * Copy up to maxBytes or end of list, switching buffers as needed. - */ - - freeCount = maxBytes; - srcPtr = cbPtr->buffer + (offset - scanned); - destPtr = buffer; - length = cbPtr->length - (offset - scanned); - while (1) { - if (length > freeCount) { - strncpy(destPtr, srcPtr, freeCount); - return maxBytes; - } else { - strncpy(destPtr, srcPtr, length); - destPtr += length; - count += length; - freeCount -= length; - } - cbPtr = cbPtr->nextPtr; - if (cbPtr == NULL) { - break; - } - srcPtr = cbPtr->buffer; - length = cbPtr->length; - } - return count; -} - -/* - *---------------------------------------------------------------------- - * - * ClipboardAppHandler -- - * - * This procedure acts as selection handler for retrievals of type - * TK_APPLICATION. It returns the name of the application that - * owns the clipboard. Note: we can't use the default Tk - * selection handler for this selection type, because the clipboard - * window isn't a "real" window and doesn't have the necessary - * information. - * - * Results: - * The return value is a count of the number of bytes - * actually stored at buffer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ClipboardAppHandler(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Pointer to TkDisplay structure. */ - int offset; /* Return selection bytes starting at this - * offset. */ - char *buffer; /* Place to store converted selection. */ - int maxBytes; /* Maximum # of bytes to store at buffer. */ -{ - TkDisplay *dispPtr = (TkDisplay *) clientData; - size_t length; - char *p; - - p = dispPtr->clipboardAppPtr->winPtr->nameUid; - length = strlen(p); - length -= offset; - if (length <= 0) { - return 0; - } - if (length > (size_t) maxBytes) { - length = maxBytes; - } - strncpy(buffer, p, length); - return length; -} - -/* - *---------------------------------------------------------------------- - * - * ClipboardWindowHandler -- - * - * This procedure acts as selection handler for retrievals of - * type TK_WINDOW. Since the clipboard doesn't correspond to - * any particular window, we just return ".". We can't use Tk's - * default handler for this selection type, because the clipboard - * window isn't a valid window. - * - * Results: - * The return value is 1, the number of non-null bytes stored - * at buffer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ClipboardWindowHandler(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Not used. */ - int offset; /* Return selection bytes starting at this - * offset. */ - char *buffer; /* Place to store converted selection. */ - int maxBytes; /* Maximum # of bytes to store at buffer. */ -{ - buffer[0] = '.'; - buffer[1] = 0; - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * ClipboardLostSel -- - * - * This procedure is invoked whenever clipboard ownership is - * claimed by another window. It just sets a flag so that we - * know the clipboard was taken away. - * - * Results: - * None. - * - * Side effects: - * The clipboard is marked as inactive. - * - *---------------------------------------------------------------------- - */ - -static void -ClipboardLostSel(clientData) - ClientData clientData; /* Pointer to TkDisplay structure. */ -{ - TkDisplay *dispPtr = (TkDisplay*) clientData; - - dispPtr->clipboardActive = 0; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ClipboardClear -- - * - * Take control of the clipboard and clear out the previous - * contents. This procedure must be invoked before any - * calls to Tk_AppendToClipboard. - * - * Results: - * A standard Tcl result. If an error occurs, an error message is - * left in interp->result. - * - * Side effects: - * From now on, requests for the CLIPBOARD selection will be - * directed to the clipboard manager routines associated with - * clipWindow for the display of tkwin. In order to guarantee - * atomicity, no event handling should occur between - * Tk_ClipboardClear and the following Tk_AppendToClipboard - * calls. This procedure may cause a user-defined LostSel command - * to be invoked when the CLIPBOARD is claimed, so any calling - * function should be reentrant at the point Tk_ClipboardClear is - * invoked. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ClipboardClear(interp, tkwin) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Window tkwin; /* Window in application that is clearing - * clipboard; identifies application and - * display. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkClipboardTarget *targetPtr, *nextTargetPtr; - TkClipboardBuffer *cbPtr, *nextCbPtr; - - if (dispPtr->clipWindow == NULL) { - int result; - - result = TkClipInit(interp, dispPtr); - if (result != TCL_OK) { - return result; - } - } - - /* - * Discard any existing clipboard data and delete the selection - * handler(s) associated with that data. - */ - - for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL; - targetPtr = nextTargetPtr) { - for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; - cbPtr = nextCbPtr) { - ckfree(cbPtr->buffer); - nextCbPtr = cbPtr->nextPtr; - ckfree((char *) cbPtr); - } - nextTargetPtr = targetPtr->nextPtr; - Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, - targetPtr->type); - ckfree((char *) targetPtr); - } - dispPtr->clipTargetPtr = NULL; - - /* - * Reclaim the clipboard selection if we lost it. - */ - - if (!dispPtr->clipboardActive) { - Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom, - ClipboardLostSel, (ClientData) dispPtr); - dispPtr->clipboardActive = 1; - } - dispPtr->clipboardAppPtr = winPtr->mainPtr; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ClipboardAppend -- - * - * Append a buffer of data to the clipboard. The first buffer of - * a given type determines the format for that type. Any successive - * appends to that type must have the same format or an error will - * be returned. Tk_ClipboardClear must be called before a sequence - * of Tk_ClipboardAppend calls can be issued. In order to guarantee - * atomicity, no event handling should occur between Tk_ClipboardClear - * and the following Tk_AppendToClipboard calls. - * - * Results: - * A standard Tcl result. If an error is returned, an error message - * is left in interp->result. - * - * Side effects: - * The specified buffer will be copied onto the end of the clipboard. - * The clipboard maintains a list of buffers which will be used to - * supply the data for a selection get request. The first time a given - * type is appended, Tk_ClipboardAppend will register a selection - * handler of the appropriate type. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ClipboardAppend(interp, tkwin, type, format, buffer) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Window tkwin; /* Window that selects a display. */ - Atom type; /* The desired conversion type for this - * clipboard item, e.g. STRING or LENGTH. */ - Atom format; /* Format in which the selection - * information should be returned to - * the requestor. */ - char* buffer; /* NULL terminated string containing the data - * to be added to the clipboard. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkClipboardTarget *targetPtr; - TkClipboardBuffer *cbPtr; - - /* - * If this application doesn't already own the clipboard, clear - * the clipboard. If we don't own the clipboard selection, claim it. - */ - - if (dispPtr->clipboardAppPtr != winPtr->mainPtr) { - Tk_ClipboardClear(interp, tkwin); - } else if (!dispPtr->clipboardActive) { - Tk_OwnSelection(dispPtr->clipWindow, dispPtr->clipboardAtom, - ClipboardLostSel, (ClientData) dispPtr); - dispPtr->clipboardActive = 1; - } - - /* - * Check to see if the specified target is already present on the - * clipboard. If it isn't, we need to create a new target; otherwise, - * we just append the new buffer to the clipboard list. - */ - - for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL; - targetPtr = targetPtr->nextPtr) { - if (targetPtr->type == type) - break; - } - if (targetPtr == NULL) { - targetPtr = (TkClipboardTarget*) ckalloc(sizeof(TkClipboardTarget)); - targetPtr->type = type; - targetPtr->format = format; - targetPtr->firstBufferPtr = targetPtr->lastBufferPtr = NULL; - targetPtr->nextPtr = dispPtr->clipTargetPtr; - dispPtr->clipTargetPtr = targetPtr; - Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, - type, ClipboardHandler, (ClientData) targetPtr, format); - } else if (targetPtr->format != format) { - Tcl_AppendResult(interp, "format \"", Tk_GetAtomName(tkwin, format), - "\" does not match current format \"", - Tk_GetAtomName(tkwin, targetPtr->format),"\" for ", - Tk_GetAtomName(tkwin, type), (char *) NULL); - return TCL_ERROR; - } - - /* - * Append a new buffer to the buffer chain. - */ - - cbPtr = (TkClipboardBuffer*) ckalloc(sizeof(TkClipboardBuffer)); - cbPtr->nextPtr = NULL; - if (targetPtr->lastBufferPtr != NULL) { - targetPtr->lastBufferPtr->nextPtr = cbPtr; - } else { - targetPtr->firstBufferPtr = cbPtr; - } - targetPtr->lastBufferPtr = cbPtr; - - cbPtr->length = strlen(buffer); - cbPtr->buffer = (char *) ckalloc((unsigned) (cbPtr->length + 1)); - strcpy(cbPtr->buffer, buffer); - - TkSelUpdateClipboard((TkWindow*)(dispPtr->clipWindow), targetPtr); - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ClipboardCmd -- - * - * This procedure is invoked to process the "clipboard" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ClipboardCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - char *path = NULL; - size_t length; - int count; - char c; - char **args; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "append", length) == 0)) { - Atom target, format; - char *targetName = NULL; - char *formatName = NULL; - - for (count = argc-2, args = argv+2; count > 1; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == '-') && (length == 2)) { - args++; - count--; - break; - } - if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) { - path = args[1]; - } else if ((c == 'f') - && (strncmp(args[0], "-format", length) == 0)) { - formatName = args[1]; - } else if ((c == 't') - && (strncmp(args[0], "-type", length) == 0)) { - targetName = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - if (count != 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " append ?options? data\"", (char *) NULL); - return TCL_ERROR; - } - if (path != NULL) { - tkwin = Tk_NameToWindow(interp, path, tkwin); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - if (targetName != NULL) { - target = Tk_InternAtom(tkwin, targetName); - } else { - target = XA_STRING; - } - if (formatName != NULL) { - format = Tk_InternAtom(tkwin, formatName); - } else { - format = XA_STRING; - } - return Tk_ClipboardAppend(interp, tkwin, target, format, args[0]); - } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) { - for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - if (count < 2) { - Tcl_AppendResult(interp, "value for \"", *args, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) { - path = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - if (count > 0) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " clear ?options?\"", (char *) NULL); - return TCL_ERROR; - } - if (path != NULL) { - tkwin = Tk_NameToWindow(interp, path, tkwin); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - return Tk_ClipboardClear(interp, tkwin); - } else { - sprintf(interp->result, - "bad option \"%.50s\": must be clear or append", - argv[1]); - return TCL_ERROR; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkClipInit -- - * - * This procedure is called to initialize the window for claiming - * clipboard ownership and for receiving selection get results. This - * function is called from tkSelect.c as well as tkClipboard.c. - * - * Results: - * The result is a standard Tcl return value, which is normally TCL_OK. - * If an error occurs then an error message is left in interp->result - * and TCL_ERROR is returned. - * - * Side effects: - * Sets up the clipWindow and related data structures. - * - *---------------------------------------------------------------------- - */ - -int -TkClipInit(interp, dispPtr) - Tcl_Interp *interp; /* Interpreter to use for error - * reporting. */ - register TkDisplay *dispPtr;/* Display to initialize. */ -{ - XSetWindowAttributes atts; - - dispPtr->clipTargetPtr = NULL; - dispPtr->clipboardActive = 0; - dispPtr->clipboardAppPtr = NULL; - - /* - * Create the window used for clipboard ownership and selection retrieval, - * and set up an event handler for it. - */ - - dispPtr->clipWindow = Tk_CreateWindow(interp, (Tk_Window) NULL, - "_clip", DisplayString(dispPtr->display)); - if (dispPtr->clipWindow == NULL) { - return TCL_ERROR; - } - atts.override_redirect = True; - Tk_ChangeWindowAttributes(dispPtr->clipWindow, CWOverrideRedirect, &atts); - Tk_MakeWindowExist(dispPtr->clipWindow); - - if (dispPtr->multipleAtom == None) { - /* - * Need to invoke selection initialization to make sure that - * atoms we depend on below are defined. - */ - - TkSelInit(dispPtr->clipWindow); - } - - /* - * Create selection handlers for types TK_APPLICATION and TK_WINDOW - * on this window. Can't use the default handlers for these types - * because this isn't a full-fledged window. - */ - - Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, - dispPtr->applicationAtom, ClipboardAppHandler, - (ClientData) dispPtr, XA_STRING); - Tk_CreateSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom, - dispPtr->windowAtom, ClipboardWindowHandler, - (ClientData) dispPtr, XA_STRING); - return TCL_OK; -} diff --git a/generic/tkCmds.c b/generic/tkCmds.c deleted file mode 100644 index 28f3202..0000000 --- a/generic/tkCmds.c +++ /dev/null @@ -1,1646 +0,0 @@ -/* - * tkCmds.c -- - * - * This file contains a collection of Tk-related Tcl commands - * that didn't fit in any particular file of the toolkit. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCmds.c,v 1.3 1998/09/14 18:23:08 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" -#include <errno.h> - -/* - * Forward declarations for procedures defined later in this file: - */ - -static TkWindow * GetToplevel _ANSI_ARGS_((Tk_Window tkwin)); -static char * WaitVariableProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static void WaitVisibilityProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void WaitWindowProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); - -/* - *---------------------------------------------------------------------- - * - * Tk_BellCmd -- - * - * This procedure is invoked to process the "bell" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_BellCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - size_t length; - - if ((argc != 1) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ?-displayof window?\"", (char *) NULL); - return TCL_ERROR; - } - - if (argc == 3) { - length = strlen(argv[1]); - if ((length < 2) || (strncmp(argv[1], "-displayof", length) != 0)) { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be -displayof", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_NameToWindow(interp, argv[2], tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - } - XBell(Tk_Display(tkwin), 0); - XForceScreenSaver(Tk_Display(tkwin), ScreenSaverReset); - XFlush(Tk_Display(tkwin)); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_BindCmd -- - * - * This procedure is invoked to process the "bind" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_BindCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - TkWindow *winPtr; - ClientData object; - - if ((argc < 2) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " window ?pattern? ?command?\"", (char *) NULL); - return TCL_ERROR; - } - if (argv[1][0] == '.') { - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); - if (winPtr == NULL) { - return TCL_ERROR; - } - object = (ClientData) winPtr->pathName; - } else { - winPtr = (TkWindow *) clientData; - object = (ClientData) Tk_GetUid(argv[1]); - } - - if (argc == 4) { - int append = 0; - unsigned long mask; - - if (argv[3][0] == 0) { - return Tk_DeleteBinding(interp, winPtr->mainPtr->bindingTable, - object, argv[2]); - } - if (argv[3][0] == '+') { - argv[3]++; - append = 1; - } - mask = Tk_CreateBinding(interp, winPtr->mainPtr->bindingTable, - object, argv[2], argv[3], append); - if (mask == 0) { - return TCL_ERROR; - } - } else if (argc == 3) { - char *command; - - command = Tk_GetBinding(interp, winPtr->mainPtr->bindingTable, - object, argv[2]); - if (command == NULL) { - Tcl_ResetResult(interp); - return TCL_OK; - } - interp->result = command; - } else { - Tk_GetAllBindings(interp, winPtr->mainPtr->bindingTable, object); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkBindEventProc -- - * - * This procedure is invoked by Tk_HandleEvent for each event; it - * causes any appropriate bindings for that event to be invoked. - * - * Results: - * None. - * - * Side effects: - * Depends on what bindings have been established with the "bind" - * command. - * - *---------------------------------------------------------------------- - */ - -void -TkBindEventProc(winPtr, eventPtr) - TkWindow *winPtr; /* Pointer to info about window. */ - XEvent *eventPtr; /* Information about event. */ -{ -#define MAX_OBJS 20 - ClientData objects[MAX_OBJS], *objPtr; - static Tk_Uid allUid = NULL; - TkWindow *topLevPtr; - int i, count; - char *p; - Tcl_HashEntry *hPtr; - - if ((winPtr->mainPtr == NULL) || (winPtr->mainPtr->bindingTable == NULL)) { - return; - } - - objPtr = objects; - if (winPtr->numTags != 0) { - /* - * Make a copy of the tags for the window, replacing window names - * with pointers to the pathName from the appropriate window. - */ - - if (winPtr->numTags > MAX_OBJS) { - objPtr = (ClientData *) ckalloc((unsigned) - (winPtr->numTags * sizeof(ClientData))); - } - for (i = 0; i < winPtr->numTags; i++) { - p = (char *) winPtr->tagPtr[i]; - if (*p == '.') { - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, p); - if (hPtr != NULL) { - p = ((TkWindow *) Tcl_GetHashValue(hPtr))->pathName; - } else { - p = NULL; - } - } - objPtr[i] = (ClientData) p; - } - count = winPtr->numTags; - } else { - objPtr[0] = (ClientData) winPtr->pathName; - objPtr[1] = (ClientData) winPtr->classUid; - for (topLevPtr = winPtr; - (topLevPtr != NULL) && !(topLevPtr->flags & TK_TOP_LEVEL); - topLevPtr = topLevPtr->parentPtr) { - /* Empty loop body. */ - } - if ((winPtr != topLevPtr) && (topLevPtr != NULL)) { - count = 4; - objPtr[2] = (ClientData) topLevPtr->pathName; - } else { - count = 3; - } - if (allUid == NULL) { - allUid = Tk_GetUid("all"); - } - objPtr[count-1] = (ClientData) allUid; - } - Tk_BindEvent(winPtr->mainPtr->bindingTable, eventPtr, (Tk_Window) winPtr, - count, objPtr); - if (objPtr != objects) { - ckfree((char *) objPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_BindtagsCmd -- - * - * This procedure is invoked to process the "bindtags" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_BindtagsCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - TkWindow *winPtr, *winPtr2; - int i, tagArgc; - char *p, **tagArgv; - - if ((argc < 2) || (argc > 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " window ?tags?\"", (char *) NULL); - return TCL_ERROR; - } - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); - if (winPtr == NULL) { - return TCL_ERROR; - } - if (argc == 2) { - if (winPtr->numTags == 0) { - Tcl_AppendElement(interp, winPtr->pathName); - Tcl_AppendElement(interp, winPtr->classUid); - for (winPtr2 = winPtr; - (winPtr2 != NULL) && !(winPtr2->flags & TK_TOP_LEVEL); - winPtr2 = winPtr2->parentPtr) { - /* Empty loop body. */ - } - if ((winPtr != winPtr2) && (winPtr2 != NULL)) { - Tcl_AppendElement(interp, winPtr2->pathName); - } - Tcl_AppendElement(interp, "all"); - } else { - for (i = 0; i < winPtr->numTags; i++) { - Tcl_AppendElement(interp, (char *) winPtr->tagPtr[i]); - } - } - return TCL_OK; - } - if (winPtr->tagPtr != NULL) { - TkFreeBindingTags(winPtr); - } - if (argv[2][0] == 0) { - return TCL_OK; - } - if (Tcl_SplitList(interp, argv[2], &tagArgc, &tagArgv) != TCL_OK) { - return TCL_ERROR; - } - winPtr->numTags = tagArgc; - winPtr->tagPtr = (ClientData *) ckalloc((unsigned) - (tagArgc * sizeof(ClientData))); - for (i = 0; i < tagArgc; i++) { - p = tagArgv[i]; - if (p[0] == '.') { - char *copy; - - /* - * Handle names starting with "." specially: store a malloc'ed - * string, rather than a Uid; at event time we'll look up the - * name in the window table and use the corresponding window, - * if there is one. - */ - - copy = (char *) ckalloc((unsigned) (strlen(p) + 1)); - strcpy(copy, p); - winPtr->tagPtr[i] = (ClientData) copy; - } else { - winPtr->tagPtr[i] = (ClientData) Tk_GetUid(p); - } - } - ckfree((char *) tagArgv); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkFreeBindingTags -- - * - * This procedure is called to free all of the binding tags - * associated with a window; typically it is only invoked where - * there are window-specific tags. - * - * Results: - * None. - * - * Side effects: - * Any binding tags for winPtr are freed. - * - *---------------------------------------------------------------------- - */ - -void -TkFreeBindingTags(winPtr) - TkWindow *winPtr; /* Window whose tags are to be released. */ -{ - int i; - char *p; - - for (i = 0; i < winPtr->numTags; i++) { - p = (char *) (winPtr->tagPtr[i]); - if (*p == '.') { - /* - * Names starting with "." are malloced rather than Uids, so - * they have to be freed. - */ - - ckfree(p); - } - } - ckfree((char *) winPtr->tagPtr); - winPtr->numTags = 0; - winPtr->tagPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DestroyCmd -- - * - * This procedure is invoked to process the "destroy" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_DestroyCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window window; - Tk_Window tkwin = (Tk_Window) clientData; - int i; - - for (i = 1; i < argc; i++) { - window = Tk_NameToWindow(interp, argv[i], tkwin); - if (window == NULL) { - Tcl_ResetResult(interp); - continue; - } - Tk_DestroyWindow(window); - if (window == tkwin) { - /* - * We just deleted the main window for the application! This - * makes it impossible to do anything more (tkwin isn't - * valid anymore). - */ - - break; - } - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_LowerCmd -- - * - * This procedure is invoked to process the "lower" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tk_LowerCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window mainwin = (Tk_Window) clientData; - Tk_Window tkwin, other; - - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window ?belowThis?\"", (char *) NULL); - return TCL_ERROR; - } - - tkwin = Tk_NameToWindow(interp, argv[1], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - if (argc == 2) { - other = NULL; - } else { - other = Tk_NameToWindow(interp, argv[2], mainwin); - if (other == NULL) { - return TCL_ERROR; - } - } - if (Tk_RestackWindow(tkwin, Below, other) != TCL_OK) { - Tcl_AppendResult(interp, "can't lower \"", argv[1], "\" below \"", - argv[2], "\"", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_RaiseCmd -- - * - * This procedure is invoked to process the "raise" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tk_RaiseCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window mainwin = (Tk_Window) clientData; - Tk_Window tkwin, other; - - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window ?aboveThis?\"", (char *) NULL); - return TCL_ERROR; - } - - tkwin = Tk_NameToWindow(interp, argv[1], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - if (argc == 2) { - other = NULL; - } else { - other = Tk_NameToWindow(interp, argv[2], mainwin); - if (other == NULL) { - return TCL_ERROR; - } - } - if (Tk_RestackWindow(tkwin, Above, other) != TCL_OK) { - Tcl_AppendResult(interp, "can't raise \"", argv[1], "\" above \"", - argv[2], "\"", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_TkObjCmd -- - * - * This procedure is invoked to process the "tk" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_TkObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ -{ - int index; - Tk_Window tkwin; - static char *optionStrings[] = { - "appname", "scaling", NULL - }; - enum options { - TK_APPNAME, TK_SCALING - }; - - tkwin = (Tk_Window) clientData; - - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); - return TCL_ERROR; - } - if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, - &index) != TCL_OK) { - return TCL_ERROR; - } - - switch ((enum options) index) { - case TK_APPNAME: { - TkWindow *winPtr; - char *string; - - winPtr = (TkWindow *) tkwin; - - if (objc > 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?newName?"); - return TCL_ERROR; - } - if (objc == 3) { - string = Tcl_GetStringFromObj(objv[2], NULL); - winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, string)); - } - Tcl_SetStringObj(Tcl_GetObjResult(interp), winPtr->nameUid, -1); - break; - } - case TK_SCALING: { - Screen *screenPtr; - int skip, width, height; - double d; - - screenPtr = Tk_Screen(tkwin); - - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip == 2) { - d = 25.4 / 72; - d *= WidthOfScreen(screenPtr); - d /= WidthMMOfScreen(screenPtr); - Tcl_SetDoubleObj(Tcl_GetObjResult(interp), d); - } else if (objc - skip == 3) { - if (Tcl_GetDoubleFromObj(interp, objv[2 + skip], &d) != TCL_OK) { - return TCL_ERROR; - } - d = (25.4 / 72) / d; - width = (int) (d * WidthOfScreen(screenPtr) + 0.5); - if (width <= 0) { - width = 1; - } - height = (int) (d * HeightOfScreen(screenPtr) + 0.5); - if (height <= 0) { - height = 1; - } - WidthMMOfScreen(screenPtr) = width; - HeightMMOfScreen(screenPtr) = height; - } else { - Tcl_WrongNumArgs(interp, 2, objv, - "?-displayof window? ?factor?"); - return TCL_ERROR; - } - break; - } - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_TkwaitCmd -- - * - * This procedure is invoked to process the "tkwait" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tk_TkwaitCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - int c, done; - size_t length; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " variable|visibility|window name\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'v') && (strncmp(argv[1], "variable", length) == 0) - && (length >= 2)) { - if (Tcl_TraceVar(interp, argv[2], - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - WaitVariableProc, (ClientData) &done) != TCL_OK) { - return TCL_ERROR; - } - done = 0; - while (!done) { - Tcl_DoOneEvent(0); - } - Tcl_UntraceVar(interp, argv[2], - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - WaitVariableProc, (ClientData) &done); - } else if ((c == 'v') && (strncmp(argv[1], "visibility", length) == 0) - && (length >= 2)) { - Tk_Window window; - - window = Tk_NameToWindow(interp, argv[2], tkwin); - if (window == NULL) { - return TCL_ERROR; - } - Tk_CreateEventHandler(window, VisibilityChangeMask|StructureNotifyMask, - WaitVisibilityProc, (ClientData) &done); - done = 0; - while (!done) { - Tcl_DoOneEvent(0); - } - if (done != 1) { - /* - * Note that we do not delete the event handler because it - * was deleted automatically when the window was destroyed. - */ - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "window \"", argv[2], - "\" was deleted before its visibility changed", - (char *) NULL); - return TCL_ERROR; - } - Tk_DeleteEventHandler(window, VisibilityChangeMask|StructureNotifyMask, - WaitVisibilityProc, (ClientData) &done); - } else if ((c == 'w') && (strncmp(argv[1], "window", length) == 0)) { - Tk_Window window; - - window = Tk_NameToWindow(interp, argv[2], tkwin); - if (window == NULL) { - return TCL_ERROR; - } - Tk_CreateEventHandler(window, StructureNotifyMask, - WaitWindowProc, (ClientData) &done); - done = 0; - while (!done) { - Tcl_DoOneEvent(0); - } - /* - * Note: there's no need to delete the event handler. It was - * deleted automatically when the window was destroyed. - */ - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be variable, visibility, or window", (char *) NULL); - return TCL_ERROR; - } - - /* - * Clear out the interpreter's result, since it may have been set - * by event handlers. - */ - - Tcl_ResetResult(interp); - return TCL_OK; -} - - /* ARGSUSED */ -static char * -WaitVariableProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -{ - int *donePtr = (int *) clientData; - - *donePtr = 1; - return (char *) NULL; -} - - /*ARGSUSED*/ -static void -WaitVisibilityProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event (not used). */ -{ - int *donePtr = (int *) clientData; - - if (eventPtr->type == VisibilityNotify) { - *donePtr = 1; - } - if (eventPtr->type == DestroyNotify) { - *donePtr = 2; - } -} - -static void -WaitWindowProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event. */ -{ - int *donePtr = (int *) clientData; - - if (eventPtr->type == DestroyNotify) { - *donePtr = 1; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_UpdateCmd -- - * - * This procedure is invoked to process the "update" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tk_UpdateCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - int flags; - TkDisplay *dispPtr; - - if (argc == 1) { - flags = TCL_DONT_WAIT; - } else if (argc == 2) { - if (strncmp(argv[1], "idletasks", strlen(argv[1])) != 0) { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be idletasks", (char *) NULL); - return TCL_ERROR; - } - flags = TCL_IDLE_EVENTS; - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ?idletasks?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Handle all pending events, sync all displays, and repeat over - * and over again until all pending events have been handled. - * Special note: it's possible that the entire application could - * be destroyed by an event handler that occurs during the update. - * Thus, don't use any information from tkwin after calling - * Tcl_DoOneEvent. - */ - - while (1) { - while (Tcl_DoOneEvent(flags) != 0) { - /* Empty loop body */ - } - for (dispPtr = tkDisplayList; dispPtr != NULL; - dispPtr = dispPtr->nextPtr) { - XSync(dispPtr->display, False); - } - if (Tcl_DoOneEvent(flags) == 0) { - break; - } - } - - /* - * Must clear the interpreter's result because event handlers could - * have executed commands. - */ - - Tcl_ResetResult(interp); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_WinfoObjCmd -- - * - * This procedure is invoked to process the "winfo" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_WinfoObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ -{ - int index, x, y, width, height, useX, useY, class, skip; - char buf[128]; - char *string; - TkWindow *winPtr; - Tk_Window tkwin; - - static TkStateMap visualMap[] = { - {PseudoColor, "pseudocolor"}, - {GrayScale, "grayscale"}, - {DirectColor, "directcolor"}, - {TrueColor, "truecolor"}, - {StaticColor, "staticcolor"}, - {StaticGray, "staticgray"}, - {-1, NULL} - }; - static char *optionStrings[] = { - "cells", "children", "class", "colormapfull", - "depth", "geometry", "height", "id", - "ismapped", "manager", "name", "parent", - "pointerx", "pointery", "pointerxy", "reqheight", - "reqwidth", "rootx", "rooty", "screen", - "screencells", "screendepth", "screenheight", "screenwidth", - "screenmmheight","screenmmwidth","screenvisual","server", - "toplevel", "viewable", "visual", "visualid", - "vrootheight", "vrootwidth", "vrootx", "vrooty", - "width", "x", "y", - - "atom", "atomname", "containing", "interps", - "pathname", - - "exists", "fpixels", "pixels", "rgb", - "visualsavailable", - - NULL - }; - enum options { - WIN_CELLS, WIN_CHILDREN, WIN_CLASS, WIN_COLORMAPFULL, - WIN_DEPTH, WIN_GEOMETRY, WIN_HEIGHT, WIN_ID, - WIN_ISMAPPED, WIN_MANAGER, WIN_NAME, WIN_PARENT, - WIN_POINTERX, WIN_POINTERY, WIN_POINTERXY, WIN_REQHEIGHT, - WIN_REQWIDTH, WIN_ROOTX, WIN_ROOTY, WIN_SCREEN, - WIN_SCREENCELLS,WIN_SCREENDEPTH,WIN_SCREENHEIGHT,WIN_SCREENWIDTH, - WIN_SCREENMMHEIGHT,WIN_SCREENMMWIDTH,WIN_SCREENVISUAL,WIN_SERVER, - WIN_TOPLEVEL, WIN_VIEWABLE, WIN_VISUAL, WIN_VISUALID, - WIN_VROOTHEIGHT,WIN_VROOTWIDTH, WIN_VROOTX, WIN_VROOTY, - WIN_WIDTH, WIN_X, WIN_Y, - - WIN_ATOM, WIN_ATOMNAME, WIN_CONTAINING, WIN_INTERPS, - WIN_PATHNAME, - - WIN_EXISTS, WIN_FPIXELS, WIN_PIXELS, WIN_RGB, - WIN_VISUALSAVAILABLE - }; - - tkwin = (Tk_Window) clientData; - - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); - return TCL_ERROR; - } - if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, - &index) != TCL_OK) { - return TCL_ERROR; - } - - if (index < WIN_ATOM) { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "window"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - } - winPtr = (TkWindow *) tkwin; - - switch ((enum options) index) { - case WIN_CELLS: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - Tk_Visual(tkwin)->map_entries); - break; - } - case WIN_CHILDREN: { - Tcl_Obj *strPtr; - - Tcl_ResetResult(interp); - winPtr = winPtr->childList; - for ( ; winPtr != NULL; winPtr = winPtr->nextPtr) { - strPtr = Tcl_NewStringObj(winPtr->pathName, -1); - Tcl_ListObjAppendElement(NULL, - Tcl_GetObjResult(interp), strPtr); - } - break; - } - case WIN_CLASS: { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_Class(tkwin), -1); - break; - } - case WIN_COLORMAPFULL: { - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), - TkpCmapStressed(tkwin, Tk_Colormap(tkwin))); - break; - } - case WIN_DEPTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Depth(tkwin)); - break; - } - case WIN_GEOMETRY: { - Tcl_ResetResult(interp); - sprintf(buf, "%dx%d+%d+%d", Tk_Width(tkwin), Tk_Height(tkwin), - Tk_X(tkwin), Tk_Y(tkwin)); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - break; - } - case WIN_HEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Height(tkwin)); - break; - } - case WIN_ID: { - Tk_MakeWindowExist(tkwin); - TkpPrintWindowId(buf, Tk_WindowId(tkwin)); - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - break; - } - case WIN_ISMAPPED: { - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), - (int) Tk_IsMapped(tkwin)); - break; - } - case WIN_MANAGER: { - Tcl_ResetResult(interp); - if (winPtr->geomMgrPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->geomMgrPtr->name, -1); - } - break; - } - case WIN_NAME: { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_Name(tkwin), -1); - break; - } - case WIN_PARENT: { - Tcl_ResetResult(interp); - if (winPtr->parentPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->parentPtr->pathName, -1); - } - break; - } - case WIN_POINTERX: { - useX = 1; - useY = 0; - goto pointerxy; - } - case WIN_POINTERY: { - useX = 0; - useY = 1; - goto pointerxy; - } - case WIN_POINTERXY: { - useX = 1; - useY = 1; - - pointerxy: - winPtr = GetToplevel(tkwin); - if (winPtr == NULL) { - x = -1; - y = -1; - } else { - TkGetPointerCoords((Tk_Window) winPtr, &x, &y); - } - Tcl_ResetResult(interp); - if (useX & useY) { - sprintf(buf, "%d %d", x, y); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - } else if (useX) { - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); - } else { - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); - } - break; - } - case WIN_REQHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_ReqHeight(tkwin)); - break; - } - case WIN_REQWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_ReqWidth(tkwin)); - break; - } - case WIN_ROOTX: { - Tk_GetRootCoords(tkwin, &x, &y); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); - break; - } - case WIN_ROOTY: { - Tk_GetRootCoords(tkwin, &x, &y); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); - break; - } - case WIN_SCREEN: { - sprintf(buf, "%d", Tk_ScreenNumber(tkwin)); - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - Tk_DisplayName(tkwin), ".", buf, NULL); - break; - } - case WIN_SCREENCELLS: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - CellsOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENDEPTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - DefaultDepthOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - HeightOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - WidthOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENMMHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - HeightMMOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENMMWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - WidthMMOfScreen(Tk_Screen(tkwin))); - break; - } - case WIN_SCREENVISUAL: { - class = DefaultVisualOfScreen(Tk_Screen(tkwin))->class; - goto visual; - } - case WIN_SERVER: { - TkGetServerInfo(interp, tkwin); - break; - } - case WIN_TOPLEVEL: { - winPtr = GetToplevel(tkwin); - if (winPtr != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->pathName, -1); - } - break; - } - case WIN_VIEWABLE: { - int viewable; - - viewable = 0; - for ( ; ; winPtr = winPtr->parentPtr) { - if ((winPtr == NULL) || !(winPtr->flags & TK_MAPPED)) { - break; - } - if (winPtr->flags & TK_TOP_LEVEL) { - viewable = 1; - break; - } - } - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), viewable); - break; - } - case WIN_VISUAL: { - class = Tk_Visual(tkwin)->class; - - visual: - string = TkFindStateString(visualMap, class); - if (string == NULL) { - string = "unknown"; - } - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), string, -1); - break; - } - case WIN_VISUALID: { - Tcl_ResetResult(interp); - sprintf(buf, "0x%x", - (unsigned int) XVisualIDFromVisual(Tk_Visual(tkwin))); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - break; - } - case WIN_VROOTHEIGHT: { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), height); - break; - } - case WIN_VROOTWIDTH: { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), width); - break; - } - case WIN_VROOTX: { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); - break; - } - case WIN_VROOTY: { - Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); - break; - } - case WIN_WIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Width(tkwin)); - break; - } - case WIN_X: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_X(tkwin)); - break; - } - case WIN_Y: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Y(tkwin)); - break; - } - - /* - * Uses -displayof. - */ - - case WIN_ATOM: { - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? name"); - return TCL_ERROR; - } - objv += skip; - string = Tcl_GetStringFromObj(objv[2], NULL); - Tcl_ResetResult(interp); - Tcl_SetLongObj(Tcl_GetObjResult(interp), - (long) Tk_InternAtom(tkwin, string)); - break; - } - case WIN_ATOMNAME: { - char *name; - long id; - - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id"); - return TCL_ERROR; - } - objv += skip; - if (Tcl_GetLongFromObj(interp, objv[2], &id) != TCL_OK) { - return TCL_ERROR; - } - Tcl_ResetResult(interp); - name = Tk_GetAtomName(tkwin, (Atom) id); - if (strcmp(name, "?bad atom?") == 0) { - string = Tcl_GetStringFromObj(objv[2], NULL); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "no atom exists with id \"", string, "\"", NULL); - return TCL_ERROR; - } - Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); - break; - } - case WIN_CONTAINING: { - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 4) { - Tcl_WrongNumArgs(interp, 2, objv, - "?-displayof window? rootX rootY"); - return TCL_ERROR; - } - objv += skip; - string = Tcl_GetStringFromObj(objv[2], NULL); - if (Tk_GetPixels(interp, tkwin, string, &x) != TCL_OK) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[3], NULL); - if (Tk_GetPixels(interp, tkwin, string, &y) != TCL_OK) { - return TCL_ERROR; - } - tkwin = Tk_CoordsToWindow(x, y, tkwin); - if (tkwin != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - Tk_PathName(tkwin), -1); - } - break; - } - case WIN_INTERPS: { - int result; - - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 2) { - Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?"); - return TCL_ERROR; - } - result = TkGetInterpNames(interp, tkwin); - return result; - } - case WIN_PATHNAME: { - int id; - - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window? id"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2 + skip], NULL); - if (TkpScanWindowId(interp, string, &id) != TCL_OK) { - return TCL_ERROR; - } - winPtr = (TkWindow *) - Tk_IdToWindow(Tk_Display(tkwin), (Window) id); - if ((winPtr == NULL) || - (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) { - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "window id \"", string, - "\" doesn't exist in this application", (char *) NULL); - return TCL_ERROR; - } - - /* - * If the window is a utility window with no associated path - * (such as a wrapper window or send communication window), just - * return an empty string. - */ - - tkwin = (Tk_Window) winPtr; - if (Tk_PathName(tkwin) != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - Tk_PathName(tkwin), -1); - } - break; - } - - /* - * objv[3] is window. - */ - - case WIN_EXISTS: { - int alive; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "window"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], NULL); - winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin); - alive = 1; - if ((winPtr == NULL) || (winPtr->flags & TK_ALREADY_DEAD)) { - alive = 0; - } - Tcl_ResetResult(interp); /* clear any error msg */ - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), alive); - break; - } - case WIN_FPIXELS: { - double mm, pixels; - - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "window number"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[3], NULL); - if (Tk_GetScreenMM(interp, tkwin, string, &mm) != TCL_OK) { - return TCL_ERROR; - } - pixels = mm * WidthOfScreen(Tk_Screen(tkwin)) - / WidthMMOfScreen(Tk_Screen(tkwin)); - Tcl_ResetResult(interp); - Tcl_SetDoubleObj(Tcl_GetObjResult(interp), pixels); - break; - } - case WIN_PIXELS: { - int pixels; - - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "window number"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[3], NULL); - if (Tk_GetPixels(interp, tkwin, string, &pixels) != TCL_OK) { - return TCL_ERROR; - } - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), pixels); - break; - } - case WIN_RGB: { - XColor *colorPtr; - - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "window colorName"); - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[3], NULL); - colorPtr = Tk_GetColor(interp, tkwin, string); - if (colorPtr == NULL) { - return TCL_ERROR; - } - sprintf(buf, "%d %d %d", colorPtr->red, colorPtr->green, - colorPtr->blue); - Tk_FreeColor(colorPtr); - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - break; - } - case WIN_VISUALSAVAILABLE: { - XVisualInfo template, *visInfoPtr; - int count, i; - char visualIdString[16]; - int includeVisualId; - Tcl_Obj *strPtr; - - if (objc == 3) { - includeVisualId = 0; - } else if ((objc == 4) - && (strcmp(Tcl_GetStringFromObj(objv[3], NULL), - "includeids") == 0)) { - includeVisualId = 1; - } else { - Tcl_WrongNumArgs(interp, 2, objv, "window ?includeids?"); - return TCL_ERROR; - } - - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - - template.screen = Tk_ScreenNumber(tkwin); - visInfoPtr = XGetVisualInfo(Tk_Display(tkwin), VisualScreenMask, - &template, &count); - Tcl_ResetResult(interp); - if (visInfoPtr == NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - "can't find any visuals for screen", -1); - return TCL_ERROR; - } - for (i = 0; i < count; i++) { - string = TkFindStateString(visualMap, visInfoPtr[i].class); - if (string == NULL) { - strcpy(buf, "unknown"); - } else { - sprintf(buf, "%s %d", string, visInfoPtr[i].depth); - } - if (includeVisualId) { - sprintf(visualIdString, " 0x%x", - (unsigned int) visInfoPtr[i].visualid); - strcat(buf, visualIdString); - } - strPtr = Tcl_NewStringObj(buf, -1); - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - strPtr); - } - XFree((char *) visInfoPtr); - break; - } - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkGetDisplayOf -- - * - * Parses a "-displayof window" option for various commands. If - * present, the literal "-displayof" should be in objv[0] and the - * window name in objv[1]. - * - * Results: - * The return value is 0 if the argument strings did not contain - * the "-displayof" option. The return value is 2 if the - * argument strings contained both the "-displayof" option and - * a valid window name. Otherwise, the return value is -1 if - * the window name was missing or did not specify a valid window. - * - * If the return value was 2, *tkwinPtr is filled with the - * token for the window specified on the command line. If the - * return value was -1, an error message is left in interp's - * result object. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkGetDisplayOf(interp, objc, objv, tkwinPtr) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. If it is present, - * "-displayof" should be in objv[0] and - * objv[1] the name of a window. */ - Tk_Window *tkwinPtr; /* On input, contains main window of - * application associated with interp. On - * output, filled with window specified as - * option to "-displayof" argument, or - * unmodified if "-displayof" argument was not - * present. */ -{ - char *string; - int length; - - if (objc < 1) { - return 0; - } - string = Tcl_GetStringFromObj(objv[0], &length); - if ((length >= 2) && (strncmp(string, "-displayof", (unsigned) length) == 0)) { - if (objc < 2) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - "value for \"-displayof\" missing", -1); - return -1; - } - string = Tcl_GetStringFromObj(objv[1], NULL); - *tkwinPtr = Tk_NameToWindow(interp, string, *tkwinPtr); - if (*tkwinPtr == NULL) { - return -1; - } - return 2; - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkDeadAppCmd -- - * - * If an application has been deleted then all Tk commands will be - * re-bound to this procedure. - * - * Results: - * A standard Tcl error is reported to let the user know that - * the application is dead. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -TkDeadAppCmd(clientData, interp, argc, argv) - ClientData clientData; /* Dummy. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tcl_AppendResult(interp, "can't invoke \"", argv[0], - "\" command: application has been destroyed", (char *) NULL); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * GetToplevel -- - * - * Retrieves the toplevel window which is the nearest ancestor of - * of the specified window. - * - * Results: - * Returns the toplevel window or NULL if the window has no - * ancestor which is a toplevel. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static TkWindow * -GetToplevel(tkwin) - Tk_Window tkwin; /* Window for which the toplevel should be - * deterined. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - - while (!(winPtr->flags & TK_TOP_LEVEL)) { - winPtr = winPtr->parentPtr; - if (winPtr == NULL) { - return NULL; - } - } - return winPtr; -} diff --git a/generic/tkColor.c b/generic/tkColor.c deleted file mode 100644 index 108bf70..0000000 --- a/generic/tkColor.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * tkColor.c -- - * - * This file maintains a database of color values for the Tk - * toolkit, in order to avoid round-trips to the server to - * map color names to pixel values. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkColor.c,v 1.2 1998/09/14 18:23:08 stanton Exp $ - */ - -#include <tkColor.h> - -/* - * A two-level data structure is used to manage the color database. - * The top level consists of one entry for each color name that is - * currently active, and the bottom level contains one entry for each - * pixel value that is still in use. The distinction between - * levels is necessary because the same pixel may have several - * different names. There are two hash tables, one used to index into - * each of the data structures. The name hash table is used when - * allocating colors, and the pixel hash table is used when freeing - * colors. - */ - - -/* - * Hash table for name -> TkColor mapping, and key structure used to - * index into that table: - */ - -static Tcl_HashTable nameTable; -typedef struct { - Tk_Uid name; /* Name of desired color. */ - Colormap colormap; /* Colormap from which color will be - * allocated. */ - Display *display; /* Display for colormap. */ -} NameKey; - -/* - * Hash table for value -> TkColor mapping, and key structure used to - * index into that table: - */ - -static Tcl_HashTable valueTable; -typedef struct { - int red, green, blue; /* Values for desired color. */ - Colormap colormap; /* Colormap from which color will be - * allocated. */ - Display *display; /* Display for colormap. */ -} ValueKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static void ColorInit _ANSI_ARGS_((void)); - -/* - *---------------------------------------------------------------------- - * - * Tk_GetColor -- - * - * Given a string name for a color, map the name to a corresponding - * XColor structure. - * - * Results: - * The return value is a pointer to an XColor structure that - * indicates the red, blue, and green intensities for the color - * given by "name", and also specifies a pixel value to use to - * draw in that color. If an error occurs, NULL is returned and - * an error message will be left in interp->result. - * - * Side effects: - * The color is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeColor so that the database is cleaned up when colors - * aren't in use anymore. - * - *---------------------------------------------------------------------- - */ - -XColor * -Tk_GetColor(interp, tkwin, name) - Tcl_Interp *interp; /* Place to leave error message if - * color can't be found. */ - Tk_Window tkwin; /* Window in which color will be used. */ - Tk_Uid name; /* Name of color to allocated (in form - * suitable for passing to XParseColor). */ -{ - NameKey nameKey; - Tcl_HashEntry *nameHashPtr; - int new; - TkColor *tkColPtr; - Display *display = Tk_Display(tkwin); - - if (!initialized) { - ColorInit(); - } - - /* - * First, check to see if there's already a mapping for this color - * name. - */ - - nameKey.name = name; - nameKey.colormap = Tk_Colormap(tkwin); - nameKey.display = display; - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); - if (!new) { - tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr); - tkColPtr->refCount++; - return &tkColPtr->color; - } - - /* - * The name isn't currently known. Map from the name to a pixel - * value. - */ - - tkColPtr = TkpGetColor(tkwin, name); - if (tkColPtr == NULL) { - if (interp != NULL) { - if (*name == '#') { - Tcl_AppendResult(interp, "invalid color name \"", name, - "\"", (char *) NULL); - } else { - Tcl_AppendResult(interp, "unknown color name \"", name, - "\"", (char *) NULL); - } - } - Tcl_DeleteHashEntry(nameHashPtr); - return (XColor *) NULL; - } - - /* - * Now create a new TkColor structure and add it to nameTable. - */ - - tkColPtr->magic = COLOR_MAGIC; - tkColPtr->gc = None; - tkColPtr->screen = Tk_Screen(tkwin); - tkColPtr->colormap = nameKey.colormap; - tkColPtr->visual = Tk_Visual(tkwin); - tkColPtr->refCount = 1; - tkColPtr->tablePtr = &nameTable; - tkColPtr->hashPtr = nameHashPtr; - Tcl_SetHashValue(nameHashPtr, tkColPtr); - - return &tkColPtr->color; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetColorByValue -- - * - * Given a desired set of red-green-blue intensities for a color, - * locate a pixel value to use to draw that color in a given - * window. - * - * Results: - * The return value is a pointer to an XColor structure that - * indicates the closest red, blue, and green intensities available - * to those specified in colorPtr, and also specifies a pixel - * value to use to draw in that color. - * - * Side effects: - * The color is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeColor, so that the database is cleaned up when colors - * aren't in use anymore. - * - *---------------------------------------------------------------------- - */ - -XColor * -Tk_GetColorByValue(tkwin, colorPtr) - Tk_Window tkwin; /* Window where color will be used. */ - XColor *colorPtr; /* Red, green, and blue fields indicate - * desired color. */ -{ - ValueKey valueKey; - Tcl_HashEntry *valueHashPtr; - int new; - TkColor *tkColPtr; - Display *display = Tk_Display(tkwin); - - if (!initialized) { - ColorInit(); - } - - /* - * First, check to see if there's already a mapping for this color - * name. - */ - - valueKey.red = colorPtr->red; - valueKey.green = colorPtr->green; - valueKey.blue = colorPtr->blue; - valueKey.colormap = Tk_Colormap(tkwin); - valueKey.display = display; - valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new); - if (!new) { - tkColPtr = (TkColor *) Tcl_GetHashValue(valueHashPtr); - tkColPtr->refCount++; - return &tkColPtr->color; - } - - /* - * The name isn't currently known. Find a pixel value for this - * color and add a new structure to valueTable. - */ - - tkColPtr = TkpGetColorByValue(tkwin, colorPtr); - tkColPtr->magic = COLOR_MAGIC; - tkColPtr->gc = None; - tkColPtr->screen = Tk_Screen(tkwin); - tkColPtr->colormap = valueKey.colormap; - tkColPtr->visual = Tk_Visual(tkwin); - tkColPtr->refCount = 1; - tkColPtr->tablePtr = &valueTable; - tkColPtr->hashPtr = valueHashPtr; - Tcl_SetHashValue(valueHashPtr, tkColPtr); - return &tkColPtr->color; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfColor -- - * - * Given a color, return a textual string identifying - * the color. - * - * Results: - * If colorPtr was created by Tk_GetColor, then the return - * value is the "string" that was used to create it. - * Otherwise the return value is a string that could have - * been passed to Tk_GetColor to allocate that color. The - * storage for the returned string is only guaranteed to - * persist up until the next call to this procedure. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfColor(colorPtr) - XColor *colorPtr; /* Color whose name is desired. */ -{ - register TkColor *tkColPtr = (TkColor *) colorPtr; - static char string[20]; - - if ((tkColPtr->magic == COLOR_MAGIC) - && (tkColPtr->tablePtr == &nameTable)) { - return ((NameKey *) tkColPtr->hashPtr->key.words)->name; - } - sprintf(string, "#%04x%04x%04x", colorPtr->red, colorPtr->green, - colorPtr->blue); - return string; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GCForColor -- - * - * Given a color allocated from this module, this procedure - * returns a GC that can be used for simple drawing with that - * color. - * - * Results: - * The return value is a GC with color set as its foreground - * color and all other fields defaulted. This GC is only valid - * as long as the color exists; it is freed automatically when - * the last reference to the color is freed. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -GC -Tk_GCForColor(colorPtr, drawable) - XColor *colorPtr; /* Color for which a GC is desired. Must - * have been allocated by Tk_GetColor or - * Tk_GetColorByName. */ - Drawable drawable; /* Drawable in which the color will be - * used (must have same screen and depth - * as the one for which the color was - * allocated). */ -{ - TkColor *tkColPtr = (TkColor *) colorPtr; - XGCValues gcValues; - - /* - * Do a quick sanity check to make sure this color was really - * allocated by Tk_GetColor. - */ - - if (tkColPtr->magic != COLOR_MAGIC) { - panic("Tk_GCForColor called with bogus color"); - } - - if (tkColPtr->gc == None) { - gcValues.foreground = tkColPtr->color.pixel; - tkColPtr->gc = XCreateGC(DisplayOfScreen(tkColPtr->screen), - drawable, GCForeground, &gcValues); - } - return tkColPtr->gc; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeColor -- - * - * This procedure is called to release a color allocated by - * Tk_GetColor. - * - * Results: - * None. - * - * Side effects: - * The reference count associated with colorPtr is deleted, and - * the color is released to X if there are no remaining uses - * for it. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeColor(colorPtr) - XColor *colorPtr; /* Color to be released. Must have been - * allocated by Tk_GetColor or - * Tk_GetColorByValue. */ -{ - register TkColor *tkColPtr = (TkColor *) colorPtr; - Screen *screen = tkColPtr->screen; - - /* - * Do a quick sanity check to make sure this color was really - * allocated by Tk_GetColor. - */ - - if (tkColPtr->magic != COLOR_MAGIC) { - panic("Tk_FreeColor called with bogus color"); - } - - tkColPtr->refCount--; - if (tkColPtr->refCount == 0) { - if (tkColPtr->gc != None) { - XFreeGC(DisplayOfScreen(screen), tkColPtr->gc); - tkColPtr->gc = None; - } - TkpFreeColor(tkColPtr); - Tcl_DeleteHashEntry(tkColPtr->hashPtr); - tkColPtr->magic = 0; - ckfree((char *) tkColPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * ColorInit -- - * - * Initialize the structure used for color management. - * - * Results: - * None. - * - * Side effects: - * Read the code. - * - *---------------------------------------------------------------------- - */ - -static void -ColorInit() -{ - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int)); -} diff --git a/generic/tkColor.h b/generic/tkColor.h deleted file mode 100644 index 8aa2e59..0000000 --- a/generic/tkColor.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * tkColor.h -- - * - * Declarations of data types and functions used by the - * Tk color module. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkColor.h,v 1.4 1998/09/14 18:23:08 stanton Exp $ - */ - -#ifndef _TKCOLOR -#define _TKCOLOR - -#include <tkInt.h> - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * One of the following data structures is used to keep track of - * each color that the color module has allocated from the X display - * server. - */ - -#define COLOR_MAGIC ((unsigned int) 0x46140277) - -typedef struct TkColor { - XColor color; /* Information about this color. */ - unsigned int magic; /* Used for quick integrity check on this - * structure. Must always have the - * value COLOR_MAGIC. */ - GC gc; /* Simple gc with this color as foreground - * color and all other fields defaulted. - * May be None. */ - Screen *screen; /* Screen where this color is valid. Used - * to delete it, and to find its display. */ - Colormap colormap; /* Colormap from which this entry was - * allocated. */ - Visual *visual; /* Visual associated with colormap. */ - int refCount; /* Number of uses of this structure. */ - Tcl_HashTable *tablePtr; /* Hash table that indexes this structure - * (needed when deleting structure). */ - Tcl_HashEntry *hashPtr; /* Pointer to hash table entry for this - * structure. (for use in deleting entry). */ -} TkColor; - -/* - * Common APIs exported from all platform-specific implementations. - */ - -#ifndef TkpFreeColor -EXTERN void TkpFreeColor _ANSI_ARGS_((TkColor *tkColPtr)); -#endif -EXTERN TkColor * TkpGetColor _ANSI_ARGS_((Tk_Window tkwin, - Tk_Uid name)); -EXTERN TkColor * TkpGetColorByValue _ANSI_ARGS_((Tk_Window tkwin, - XColor *colorPtr)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKCOLOR */ diff --git a/generic/tkConfig.c b/generic/tkConfig.c deleted file mode 100644 index 9714feb..0000000 --- a/generic/tkConfig.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * tkConfig.c -- - * - * This file contains the Tk_ConfigureWidget procedure. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkConfig.c,v 1.2 1998/09/14 18:23:08 stanton Exp $ - */ - -#include "tkPort.h" -#include "tk.h" - -/* - * Values for "flags" field of Tk_ConfigSpec structures. Be sure - * to coordinate these values with those defined in tk.h - * (TK_CONFIG_COLOR_ONLY, etc.). There must not be overlap! - * - * INIT - Non-zero means (char *) things have been - * converted to Tk_Uid's. - */ - -#define INIT 0x20 - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - Tk_Uid value, int valueIsUid, char *widgRec)); -static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp, - Tk_ConfigSpec *specs, char *argvName, - int needFlags, int hateFlags)); -static char * FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - char *widgRec)); -static char * FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - char *widgRec, char *buffer, - Tcl_FreeProc **freeProcPtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_ConfigureWidget -- - * - * Process command-line options and database options to - * fill in fields of a widget record with resources and - * other parameters. - * - * Results: - * A standard Tcl return value. In case of an error, - * interp->result will hold an error message. - * - * Side effects: - * The fields of widgRec get filled in with information - * from argc/argv and the option database. Old information - * in widgRec's fields gets recycled. - * - *-------------------------------------------------------------- - */ - -int -Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window containing widget (needed to - * set up X resources). */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Command-line options. */ - char *widgRec; /* Record whose fields are to be - * modified. Values must be properly - * initialized. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. Also, - * may have TK_CONFIG_ARGV_ONLY set. */ -{ - register Tk_ConfigSpec *specPtr; - Tk_Uid value; /* Value of option from database. */ - int needFlags; /* Specs must contain this set of flags - * or else they are not considered. */ - int hateFlags; /* If a spec contains any bits here, it's - * not considered. */ - - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; - } - - /* - * Pass one: scan through all the option specs, replacing strings - * with Tk_Uids (if this hasn't been done already) and clearing - * the TK_CONFIG_OPTION_SPECIFIED flags. - */ - - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) { - if (specPtr->dbName != NULL) { - specPtr->dbName = Tk_GetUid(specPtr->dbName); - } - if (specPtr->dbClass != NULL) { - specPtr->dbClass = Tk_GetUid(specPtr->dbClass); - } - if (specPtr->defValue != NULL) { - specPtr->defValue = Tk_GetUid(specPtr->defValue); - } - } - specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED) - | INIT; - } - - /* - * Pass two: scan through all of the arguments, processing those - * that match entries in the specs. - */ - - for ( ; argc > 0; argc -= 2, argv += 2) { - specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; - } - - /* - * Process the entry. - */ - - if (argc < 2) { - Tcl_AppendResult(interp, "value for \"", *argv, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) { - char msg[100]; - - sprintf(msg, "\n (processing \"%.40s\" option)", - specPtr->argvName); - Tcl_AddErrorInfo(interp, msg); - return TCL_ERROR; - } - specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED; - } - - /* - * Pass three: scan through all of the specs again; if no - * command-line argument matched a spec, then check for info - * in the option database. If there was nothing in the - * database, then use the default. - */ - - if (!(flags & TK_CONFIG_ARGV_ONLY)) { - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) - || (specPtr->argvName == NULL) - || (specPtr->type == TK_CONFIG_SYNONYM)) { - continue; - } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; - } - value = NULL; - if (specPtr->dbName != NULL) { - value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); - } - if (value != NULL) { - if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != - TCL_OK) { - char msg[200]; - - sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", - "database entry for", - specPtr->dbName, Tk_PathName(tkwin)); - Tcl_AddErrorInfo(interp, msg); - return TCL_ERROR; - } - } else { - value = specPtr->defValue; - if ((value != NULL) && !(specPtr->specFlags - & TK_CONFIG_DONT_SET_DEFAULT)) { - if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != - TCL_OK) { - char msg[200]; - - sprintf(msg, - "\n (%s \"%.50s\" in widget \"%.50s\")", - "default value for", - specPtr->dbName, Tk_PathName(tkwin)); - Tcl_AddErrorInfo(interp, msg); - return TCL_ERROR; - } - } - } - } - } - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * FindConfigSpec -- - * - * Search through a table of configuration specs, looking for - * one that matches a given argvName. - * - * Results: - * The return value is a pointer to the matching entry, or NULL - * if nothing matched. In that case an error message is left - * in interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static Tk_ConfigSpec * -FindConfigSpec(interp, specs, argvName, needFlags, hateFlags) - Tcl_Interp *interp; /* Used for reporting errors. */ - Tk_ConfigSpec *specs; /* Pointer to table of configuration - * specifications for a widget. */ - char *argvName; /* Name (suitable for use in a "config" - * command) identifying particular option. */ - int needFlags; /* Flags that must be present in matching - * entry. */ - int hateFlags; /* Flags that must NOT be present in - * matching entry. */ -{ - register Tk_ConfigSpec *specPtr; - register char c; /* First character of current argument. */ - Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ - size_t length; - - c = argvName[1]; - length = strlen(argvName); - matchPtr = NULL; - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if (specPtr->argvName == NULL) { - continue; - } - if ((specPtr->argvName[1] != c) - || (strncmp(specPtr->argvName, argvName, length) != 0)) { - continue; - } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; - } - if (specPtr->argvName[length] == 0) { - matchPtr = specPtr; - goto gotMatch; - } - if (matchPtr != NULL) { - Tcl_AppendResult(interp, "ambiguous option \"", argvName, - "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; - } - matchPtr = specPtr; - } - - if (matchPtr == NULL) { - Tcl_AppendResult(interp, "unknown option \"", argvName, - "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; - } - - /* - * Found a matching entry. If it's a synonym, then find the - * entry that it's a synonym for. - */ - - gotMatch: - specPtr = matchPtr; - if (specPtr->type == TK_CONFIG_SYNONYM) { - for (specPtr = specs; ; specPtr++) { - if (specPtr->type == TK_CONFIG_END) { - Tcl_AppendResult(interp, - "couldn't find synonym for option \"", - argvName, "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; - } - if ((specPtr->dbName == matchPtr->dbName) - && (specPtr->type != TK_CONFIG_SYNONYM) - && ((specPtr->specFlags & needFlags) == needFlags) - && !(specPtr->specFlags & hateFlags)) { - break; - } - } - } - return specPtr; -} - -/* - *-------------------------------------------------------------- - * - * DoConfig -- - * - * This procedure applies a single configuration option - * to a widget record. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * WidgRec is modified as indicated by specPtr and value. - * The old value is recycled, if that is appropriate for - * the value type. - * - *-------------------------------------------------------------- - */ - -static int -DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window containing widget (needed to - * set up X resources). */ - Tk_ConfigSpec *specPtr; /* Specifier to apply. */ - char *value; /* Value to use to fill in widgRec. */ - int valueIsUid; /* Non-zero means value is a Tk_Uid; - * zero means it's an ordinary string. */ - char *widgRec; /* Record whose fields are to be - * modified. Values must be properly - * initialized. */ -{ - char *ptr; - Tk_Uid uid; - int nullValue; - - nullValue = 0; - if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) { - nullValue = 1; - } - - do { - ptr = widgRec + specPtr->offset; - switch (specPtr->type) { - case TK_CONFIG_BOOLEAN: - if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_INT: - if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_DOUBLE: - if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_STRING: { - char *old, *new; - - if (nullValue) { - new = NULL; - } else { - new = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(new, value); - } - old = *((char **) ptr); - if (old != NULL) { - ckfree(old); - } - *((char **) ptr) = new; - break; - } - case TK_CONFIG_UID: - if (nullValue) { - *((Tk_Uid *) ptr) = NULL; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - *((Tk_Uid *) ptr) = uid; - } - break; - case TK_CONFIG_COLOR: { - XColor *newPtr, *oldPtr; - - if (nullValue) { - newPtr = NULL; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - newPtr = Tk_GetColor(interp, tkwin, uid); - if (newPtr == NULL) { - return TCL_ERROR; - } - } - oldPtr = *((XColor **) ptr); - if (oldPtr != NULL) { - Tk_FreeColor(oldPtr); - } - *((XColor **) ptr) = newPtr; - break; - } - case TK_CONFIG_FONT: { - Tk_Font new; - - if (nullValue) { - new = NULL; - } else { - new = Tk_GetFont(interp, tkwin, value); - if (new == NULL) { - return TCL_ERROR; - } - } - Tk_FreeFont(*((Tk_Font *) ptr)); - *((Tk_Font *) ptr) = new; - break; - } - case TK_CONFIG_BITMAP: { - Pixmap new, old; - - if (nullValue) { - new = None; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_GetBitmap(interp, tkwin, uid); - if (new == None) { - return TCL_ERROR; - } - } - old = *((Pixmap *) ptr); - if (old != None) { - Tk_FreeBitmap(Tk_Display(tkwin), old); - } - *((Pixmap *) ptr) = new; - break; - } - case TK_CONFIG_BORDER: { - Tk_3DBorder new, old; - - if (nullValue) { - new = NULL; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_Get3DBorder(interp, tkwin, uid); - if (new == NULL) { - return TCL_ERROR; - } - } - old = *((Tk_3DBorder *) ptr); - if (old != NULL) { - Tk_Free3DBorder(old); - } - *((Tk_3DBorder *) ptr) = new; - break; - } - case TK_CONFIG_RELIEF: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: { - Tk_Cursor new, old; - - if (nullValue) { - new = None; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_GetCursor(interp, tkwin, uid); - if (new == None) { - return TCL_ERROR; - } - } - old = *((Tk_Cursor *) ptr); - if (old != None) { - Tk_FreeCursor(Tk_Display(tkwin), old); - } - *((Tk_Cursor *) ptr) = new; - if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) { - Tk_DefineCursor(tkwin, new); - } - break; - } - case TK_CONFIG_JUSTIFY: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_ANCHOR: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_CAP_STYLE: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_JOIN_STYLE: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_PIXELS: - if (Tk_GetPixels(interp, tkwin, value, (int *) ptr) - != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_MM: - if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr) - != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_WINDOW: { - Tk_Window tkwin2; - - if (nullValue) { - tkwin2 = NULL; - } else { - tkwin2 = Tk_NameToWindow(interp, value, tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - } - *((Tk_Window *) ptr) = tkwin2; - break; - } - case TK_CONFIG_CUSTOM: - if ((*specPtr->customPtr->parseProc)( - specPtr->customPtr->clientData, interp, tkwin, - value, widgRec, specPtr->offset) != TCL_OK) { - return TCL_ERROR; - } - break; - default: { - sprintf(interp->result, "bad config table: unknown type %d", - specPtr->type); - return TCL_ERROR; - } - } - specPtr++; - } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END)); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_ConfigureInfo -- - * - * Return information about the configuration options - * for a window, and their current values. - * - * Results: - * Always returns TCL_OK. Interp->result will be modified - * hold a description of either a single configuration option - * available for "widgRec" via "specs", or all the configuration - * options available. In the "all" case, the result will - * available for "widgRec" via "specs". The result will - * be a list, each of whose entries describes one option. - * Each entry will itself be a list containing the option's - * name for use on command lines, database name, database - * class, default value, and current value (empty string - * if none). For options that are synonyms, the list will - * contain only two values: name and synonym name. If the - * "name" argument is non-NULL, then the only information - * returned is that for the named argument (i.e. the corresponding - * entry in the overall list is returned). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window corresponding to widgRec. */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current - * values for options. */ - char *argvName; /* If non-NULL, indicates a single option - * whose info is to be returned. Otherwise - * info is returned for all options. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ -{ - register Tk_ConfigSpec *specPtr; - int needFlags, hateFlags; - char *list; - char *leader = "{"; - - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; - } - - /* - * If information is only wanted for a single configuration - * spec, then handle that one spec specially. - */ - - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - if (argvName != NULL) { - specPtr = FindConfigSpec(interp, specs, argvName, needFlags, - hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; - } - interp->result = FormatConfigInfo(interp, tkwin, specPtr, widgRec); - interp->freeProc = TCL_DYNAMIC; - return TCL_OK; - } - - /* - * Loop through all the specs, creating a big list with all - * their information. - */ - - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((argvName != NULL) && (specPtr->argvName != argvName)) { - continue; - } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; - } - if (specPtr->argvName == NULL) { - continue; - } - list = FormatConfigInfo(interp, tkwin, specPtr, widgRec); - Tcl_AppendResult(interp, leader, list, "}", (char *) NULL); - ckfree(list); - leader = " {"; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * FormatConfigInfo -- - * - * Create a valid Tcl list holding the configuration information - * for a single configuration option. - * - * Results: - * A Tcl list, dynamically allocated. The caller is expected to - * arrange for this list to be freed eventually. - * - * Side effects: - * Memory is allocated. - * - *-------------------------------------------------------------- - */ - -static char * -FormatConfigInfo(interp, tkwin, specPtr, widgRec) - Tcl_Interp *interp; /* Interpreter to use for things - * like floating-point precision. */ - Tk_Window tkwin; /* Window corresponding to widget. */ - register Tk_ConfigSpec *specPtr; /* Pointer to information describing - * option. */ - char *widgRec; /* Pointer to record holding current - * values of info for widget. */ -{ - char *argv[6], *result; - char buffer[200]; - Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL; - - argv[0] = specPtr->argvName; - argv[1] = specPtr->dbName; - argv[2] = specPtr->dbClass; - argv[3] = specPtr->defValue; - if (specPtr->type == TK_CONFIG_SYNONYM) { - return Tcl_Merge(2, argv); - } - argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, - &freeProc); - if (argv[1] == NULL) { - argv[1] = ""; - } - if (argv[2] == NULL) { - argv[2] = ""; - } - if (argv[3] == NULL) { - argv[3] = ""; - } - if (argv[4] == NULL) { - argv[4] = ""; - } - result = Tcl_Merge(5, argv); - if (freeProc != NULL) { - if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) { - ckfree(argv[4]); - } else { - (*freeProc)(argv[4]); - } - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * FormatConfigValue -- - * - * This procedure formats the current value of a configuration - * option. - * - * Results: - * The return value is the formatted value of the option given - * by specPtr and widgRec. If the value is static, so that it - * need not be freed, *freeProcPtr will be set to NULL; otherwise - * *freeProcPtr will be set to the address of a procedure to - * free the result, and the caller must invoke this procedure - * when it is finished with the result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static char * -FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr) - Tcl_Interp *interp; /* Interpreter for use in real conversions. */ - Tk_Window tkwin; /* Window corresponding to widget. */ - Tk_ConfigSpec *specPtr; /* Pointer to information describing option. - * Must not point to a synonym option. */ - char *widgRec; /* Pointer to record holding current - * values of info for widget. */ - char *buffer; /* Static buffer to use for small values. - * Must have at least 200 bytes of storage. */ - Tcl_FreeProc **freeProcPtr; /* Pointer to word to fill in with address - * of procedure to free the result, or NULL - * if result is static. */ -{ - char *ptr, *result; - - *freeProcPtr = NULL; - ptr = widgRec + specPtr->offset; - result = ""; - switch (specPtr->type) { - case TK_CONFIG_BOOLEAN: - if (*((int *) ptr) == 0) { - result = "0"; - } else { - result = "1"; - } - break; - case TK_CONFIG_INT: - sprintf(buffer, "%d", *((int *) ptr)); - result = buffer; - break; - case TK_CONFIG_DOUBLE: - Tcl_PrintDouble(interp, *((double *) ptr), buffer); - result = buffer; - break; - case TK_CONFIG_STRING: - result = (*(char **) ptr); - if (result == NULL) { - result = ""; - } - break; - case TK_CONFIG_UID: { - Tk_Uid uid = *((Tk_Uid *) ptr); - if (uid != NULL) { - result = uid; - } - break; - } - case TK_CONFIG_COLOR: { - XColor *colorPtr = *((XColor **) ptr); - if (colorPtr != NULL) { - result = Tk_NameOfColor(colorPtr); - } - break; - } - case TK_CONFIG_FONT: { - Tk_Font tkfont = *((Tk_Font *) ptr); - if (tkfont != NULL) { - result = Tk_NameOfFont(tkfont); - } - break; - } - case TK_CONFIG_BITMAP: { - Pixmap pixmap = *((Pixmap *) ptr); - if (pixmap != None) { - result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap); - } - break; - } - case TK_CONFIG_BORDER: { - Tk_3DBorder border = *((Tk_3DBorder *) ptr); - if (border != NULL) { - result = Tk_NameOf3DBorder(border); - } - break; - } - case TK_CONFIG_RELIEF: - result = Tk_NameOfRelief(*((int *) ptr)); - break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: { - Tk_Cursor cursor = *((Tk_Cursor *) ptr); - if (cursor != None) { - result = Tk_NameOfCursor(Tk_Display(tkwin), cursor); - } - break; - } - case TK_CONFIG_JUSTIFY: - result = Tk_NameOfJustify(*((Tk_Justify *) ptr)); - break; - case TK_CONFIG_ANCHOR: - result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr)); - break; - case TK_CONFIG_CAP_STYLE: - result = Tk_NameOfCapStyle(*((int *) ptr)); - break; - case TK_CONFIG_JOIN_STYLE: - result = Tk_NameOfJoinStyle(*((int *) ptr)); - break; - case TK_CONFIG_PIXELS: - sprintf(buffer, "%d", *((int *) ptr)); - result = buffer; - break; - case TK_CONFIG_MM: - Tcl_PrintDouble(interp, *((double *) ptr), buffer); - result = buffer; - break; - case TK_CONFIG_WINDOW: { - Tk_Window tkwin; - - tkwin = *((Tk_Window *) ptr); - if (tkwin != NULL) { - result = Tk_PathName(tkwin); - } - break; - } - case TK_CONFIG_CUSTOM: - result = (*specPtr->customPtr->printProc)( - specPtr->customPtr->clientData, tkwin, widgRec, - specPtr->offset, freeProcPtr); - break; - default: - result = "?? unknown type ??"; - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ConfigureValue -- - * - * This procedure returns the current value of a configuration - * option for a widget. - * - * Results: - * The return value is a standard Tcl completion code (TCL_OK or - * TCL_ERROR). Interp->result will be set to hold either the value - * of the option given by argvName (if TCL_OK is returned) or - * an error message (if TCL_ERROR is returned). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window corresponding to widgRec. */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current - * values for options. */ - char *argvName; /* Gives the command-line name for the - * option whose value is to be returned. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ -{ - Tk_ConfigSpec *specPtr; - int needFlags, hateFlags; - - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; - } - specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; - } - interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec, - interp->result, &interp->freeProc); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeOptions -- - * - * Free up all resources associated with configuration options. - * - * Results: - * None. - * - * Side effects: - * Any resource in widgRec that is controlled by a configuration - * option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate - * fashion. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -Tk_FreeOptions(specs, widgRec, display, needFlags) - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current - * values for options. */ - Display *display; /* X display; needed for freeing some - * resources. */ - int needFlags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ -{ - register Tk_ConfigSpec *specPtr; - char *ptr; - - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((specPtr->specFlags & needFlags) != needFlags) { - continue; - } - ptr = widgRec + specPtr->offset; - switch (specPtr->type) { - case TK_CONFIG_STRING: - if (*((char **) ptr) != NULL) { - ckfree(*((char **) ptr)); - *((char **) ptr) = NULL; - } - break; - case TK_CONFIG_COLOR: - if (*((XColor **) ptr) != NULL) { - Tk_FreeColor(*((XColor **) ptr)); - *((XColor **) ptr) = NULL; - } - break; - case TK_CONFIG_FONT: - Tk_FreeFont(*((Tk_Font *) ptr)); - *((Tk_Font *) ptr) = NULL; - break; - case TK_CONFIG_BITMAP: - if (*((Pixmap *) ptr) != None) { - Tk_FreeBitmap(display, *((Pixmap *) ptr)); - *((Pixmap *) ptr) = None; - } - break; - case TK_CONFIG_BORDER: - if (*((Tk_3DBorder *) ptr) != NULL) { - Tk_Free3DBorder(*((Tk_3DBorder *) ptr)); - *((Tk_3DBorder *) ptr) = NULL; - } - break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: - if (*((Tk_Cursor *) ptr) != None) { - Tk_FreeCursor(display, *((Tk_Cursor *) ptr)); - *((Tk_Cursor *) ptr) = None; - } - } - } -} diff --git a/generic/tkConsole.c b/generic/tkConsole.c deleted file mode 100644 index 597b16e..0000000 --- a/generic/tkConsole.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * tkConsole.c -- - * - * This file implements a Tcl console for systems that may not - * otherwise have access to a console. It uses the Text widget - * and provides special access via a console command. - * - * Copyright (c) 1995-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkConsole.c,v 1.2 1998/09/14 18:23:08 stanton Exp $ - */ - -#include "tk.h" -#include <string.h> - -/* - * A data structure of the following type holds information for each console - * which a handler (i.e. a Tcl command) has been defined for a particular - * top-level window. - */ - -typedef struct ConsoleInfo { - Tcl_Interp *consoleInterp; /* Interpreter for the console. */ - Tcl_Interp *interp; /* Interpreter to send console commands. */ -} ConsoleInfo; - -static Tcl_Interp *gStdoutInterp = NULL; - -/* - * Forward declarations for procedures defined later in this file: - * - * The first three will be used in the tk app shells... - */ - -void TkConsoleCreate _ANSI_ARGS_((void)); -int TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp)); -void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp, - int devId, char *buffer, long size)); - -static int ConsoleCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void ConsoleDeleteProc _ANSI_ARGS_((ClientData clientData)); -static void ConsoleEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int InterpreterCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); - -static int ConsoleInput _ANSI_ARGS_((ClientData instanceData, - char *buf, int toRead, int *errorCode)); -static int ConsoleOutput _ANSI_ARGS_((ClientData instanceData, - char *buf, int toWrite, int *errorCode)); -static int ConsoleClose _ANSI_ARGS_((ClientData instanceData, - Tcl_Interp *interp)); -static void ConsoleWatch _ANSI_ARGS_((ClientData instanceData, - int mask)); -static int ConsoleHandle _ANSI_ARGS_((ClientData instanceData, - int direction, ClientData *handlePtr)); - -/* - * This structure describes the channel type structure for file based IO: - */ - -static Tcl_ChannelType consoleChannelType = { - "console", /* Type name. */ - NULL, /* Always non-blocking.*/ - ConsoleClose, /* Close proc. */ - ConsoleInput, /* Input proc. */ - ConsoleOutput, /* Output proc. */ - NULL, /* Seek proc. */ - NULL, /* Set option proc. */ - NULL, /* Get option proc. */ - ConsoleWatch, /* Watch for events on console. */ - ConsoleHandle, /* Get a handle from the device. */ -}; - -/* - *---------------------------------------------------------------------- - * - * TkConsoleCreate -- - * - * Create the console channels and install them as the standard - * channels. All I/O will be discarded until TkConsoleInit is - * called to attach the console to a text widget. - * - * Results: - * None. - * - * Side effects: - * Creates the console channel and installs it as the standard - * channels. - * - *---------------------------------------------------------------------- - */ - -void -TkConsoleCreate() -{ - Tcl_Channel consoleChannel; - - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0", - (ClientData) TCL_STDIN, TCL_READABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); - } - Tcl_SetStdChannel(consoleChannel, TCL_STDIN); - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1", - (ClientData) TCL_STDOUT, TCL_WRITABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); - } - Tcl_SetStdChannel(consoleChannel, TCL_STDOUT); - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2", - (ClientData) TCL_STDERR, TCL_WRITABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); - } - Tcl_SetStdChannel(consoleChannel, TCL_STDERR); -} - -/* - *---------------------------------------------------------------------- - * - * TkConsoleInit -- - * - * Initialize the console. This code actually creates a new - * application and associated interpreter. This effectivly hides - * the implementation from the main application. - * - * Results: - * None. - * - * Side effects: - * A new console it created. - * - *---------------------------------------------------------------------- - */ - -int -TkConsoleInit(interp) - Tcl_Interp *interp; /* Interpreter to use for prompting. */ -{ - Tcl_Interp *consoleInterp; - ConsoleInfo *info; - Tk_Window mainWindow = Tk_MainWindow(interp); -#ifdef MAC_TCL - static char initCmd[] = "source -rsrc {Console}"; -#else - static char initCmd[] = "source $tk_library/console.tcl"; -#endif - - consoleInterp = Tcl_CreateInterp(); - if (consoleInterp == NULL) { - goto error; - } - - /* - * Initialized Tcl and Tk. - */ - - if (Tcl_Init(consoleInterp) != TCL_OK) { - goto error; - } - if (Tk_Init(consoleInterp) != TCL_OK) { - goto error; - } - gStdoutInterp = interp; - - /* - * Add console commands to the interp - */ - info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo)); - info->interp = interp; - info->consoleInterp = consoleInterp; - Tcl_CreateCommand(interp, "console", ConsoleCmd, (ClientData) info, - (Tcl_CmdDeleteProc *) ConsoleDeleteProc); - Tcl_CreateCommand(consoleInterp, "consoleinterp", InterpreterCmd, - (ClientData) info, (Tcl_CmdDeleteProc *) NULL); - - Tk_CreateEventHandler(mainWindow, StructureNotifyMask, ConsoleEventProc, - (ClientData) info); - - Tcl_Preserve((ClientData) consoleInterp); - if (Tcl_Eval(consoleInterp, initCmd) == TCL_ERROR) { - /* goto error; -- no problem for now... */ - printf("Eval error: %s", consoleInterp->result); - } - Tcl_Release((ClientData) consoleInterp); - return TCL_OK; - - error: - if (consoleInterp != NULL) { - Tcl_DeleteInterp(consoleInterp); - } - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleOutput-- - * - * Writes the given output on the IO channel. Returns count of how - * many characters were actually written, and an error indication. - * - * Results: - * A count of how many characters were written is returned and an - * error indication is returned in an output argument. - * - * Side effects: - * Writes output on the actual channel. - * - *---------------------------------------------------------------------- - */ - -static int -ConsoleOutput(instanceData, buf, toWrite, errorCode) - ClientData instanceData; /* Indicates which device to use. */ - char *buf; /* The data buffer. */ - int toWrite; /* How many bytes to write? */ - int *errorCode; /* Where to store error code. */ -{ - *errorCode = 0; - Tcl_SetErrno(0); - - if (gStdoutInterp != NULL) { - TkConsolePrint(gStdoutInterp, (int) instanceData, buf, toWrite); - } - - return toWrite; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleInput -- - * - * Read input from the console. Not currently implemented. - * - * Results: - * Always returns EOF. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ConsoleInput(instanceData, buf, bufSize, errorCode) - ClientData instanceData; /* Unused. */ - char *buf; /* Where to store data read. */ - int bufSize; /* How much space is available - * in the buffer? */ - int *errorCode; /* Where to store error code. */ -{ - return 0; /* Always return EOF. */ -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleClose -- - * - * Closes the IO channel. - * - * Results: - * Always returns 0 (success). - * - * Side effects: - * Frees the dummy file associated with the channel. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ConsoleClose(instanceData, interp) - ClientData instanceData; /* Unused. */ - Tcl_Interp *interp; /* Unused. */ -{ - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleWatch -- - * - * Called by the notifier to set up the console device so that - * events will be noticed. Since there are no events on the - * console, this routine just returns without doing anything. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ConsoleWatch(instanceData, mask) - ClientData instanceData; /* Device ID for the channel. */ - int mask; /* OR-ed combination of - * TCL_READABLE, TCL_WRITABLE and - * TCL_EXCEPTION, for the events - * we are interested in. */ -{ -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleHandle -- - * - * Invoked by the generic IO layer to get a handle from a channel. - * Because console channels are not devices, this function always - * fails. - * - * Results: - * Always returns TCL_ERROR. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ConsoleHandle(instanceData, direction, handlePtr) - ClientData instanceData; /* Device ID for the channel. */ - int direction; /* TCL_READABLE or TCL_WRITABLE to indicate - * which direction of the channel is being - * requested. */ - ClientData *handlePtr; /* Where to store handle */ -{ - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleCmd -- - * - * The console command implements a Tcl interface to the various console - * options. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ConsoleCmd(clientData, interp, argc, argv) - ClientData clientData; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - ConsoleInfo *info = (ConsoleInfo *) clientData; - char c; - int length; - int result; - Tcl_Interp *consoleInterp; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - - c = argv[1][0]; - length = strlen(argv[1]); - result = TCL_OK; - consoleInterp = info->consoleInterp; - Tcl_Preserve((ClientData) consoleInterp); - if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) { - Tcl_DString dString; - - Tcl_DStringInit(&dString); - Tcl_DStringAppend(&dString, "wm title . ", -1); - if (argc == 3) { - Tcl_DStringAppendElement(&dString, argv[2]); - } - Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); - Tcl_DStringFree(&dString); - } else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) { - Tcl_Eval(info->consoleInterp, "wm withdraw ."); - } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) { - Tcl_Eval(info->consoleInterp, "wm deiconify ."); - } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) { - if (argc == 3) { - Tcl_Eval(info->consoleInterp, argv[2]); - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " eval command\"", (char *) NULL); - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be hide, show, or title", - (char *) NULL); - result = TCL_ERROR; - } - Tcl_Release((ClientData) consoleInterp); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * InterpreterCmd -- - * - * This command allows the console interp to communicate with the - * main interpreter. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -InterpreterCmd(clientData, interp, argc, argv) - ClientData clientData; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - ConsoleInfo *info = (ConsoleInfo *) clientData; - char c; - int length; - int result; - Tcl_Interp *otherInterp; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - - c = argv[1][0]; - length = strlen(argv[1]); - otherInterp = info->interp; - Tcl_Preserve((ClientData) otherInterp); - if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) { - result = Tcl_GlobalEval(otherInterp, argv[2]); - Tcl_AppendResult(interp, otherInterp->result, (char *) NULL); - } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) { - Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL); - result = TCL_OK; - Tcl_AppendResult(interp, otherInterp->result, (char *) NULL); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be eval or record", - (char *) NULL); - result = TCL_ERROR; - } - Tcl_Release((ClientData) otherInterp); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDeleteProc -- - * - * If the console command is deleted we destroy the console window - * and all associated data structures. - * - * Results: - * None. - * - * Side effects: - * A new console it created. - * - *---------------------------------------------------------------------- - */ - -void -ConsoleDeleteProc(clientData) - ClientData clientData; -{ - ConsoleInfo *info = (ConsoleInfo *) clientData; - - Tcl_DeleteInterp(info->consoleInterp); - info->consoleInterp = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleEventProc -- - * - * This event procedure is registered on the main window of the - * slave interpreter. If the user or a running script causes the - * main window to be destroyed, then we need to inform the console - * interpreter by invoking "tkConsoleExit". - * - * Results: - * None. - * - * Side effects: - * Invokes the "tkConsoleExit" procedure in the console interp. - * - *---------------------------------------------------------------------- - */ - -static void -ConsoleEventProc(clientData, eventPtr) - ClientData clientData; - XEvent *eventPtr; -{ - ConsoleInfo *info = (ConsoleInfo *) clientData; - Tcl_Interp *consoleInterp; - - if (eventPtr->type == DestroyNotify) { - consoleInterp = info->consoleInterp; - - /* - * It is possible that the console interpreter itself has - * already been deleted. In that case the consoleInterp - * field will be set to NULL. If the interpreter is already - * gone, we do not have to do any work here. - */ - - if (consoleInterp == (Tcl_Interp *) NULL) { - return; - } - Tcl_Preserve((ClientData) consoleInterp); - Tcl_Eval(consoleInterp, "tkConsoleExit"); - Tcl_Release((ClientData) consoleInterp); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkConsolePrint -- - * - * Prints to the give text to the console. Given the main interp - * this functions find the appropiate console interp and forwards - * the text to be added to that console. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkConsolePrint(interp, devId, buffer, size) - Tcl_Interp *interp; /* Main interpreter. */ - int devId; /* TCL_STDOUT for stdout, TCL_STDERR for - * stderr. */ - char *buffer; /* Text buffer. */ - long size; /* Size of text buffer. */ -{ - Tcl_DString command, output; - Tcl_CmdInfo cmdInfo; - char *cmd; - ConsoleInfo *info; - Tcl_Interp *consoleInterp; - int result; - - if (interp == NULL) { - return; - } - - if (devId == TCL_STDERR) { - cmd = "tkConsoleOutput stderr "; - } else { - cmd = "tkConsoleOutput stdout "; - } - - result = Tcl_GetCommandInfo(interp, "console", &cmdInfo); - if (result == 0) { - return; - } - info = (ConsoleInfo *) cmdInfo.clientData; - - Tcl_DStringInit(&output); - Tcl_DStringAppend(&output, buffer, size); - - Tcl_DStringInit(&command); - Tcl_DStringAppend(&command, cmd, strlen(cmd)); - Tcl_DStringAppendElement(&command, output.string); - - consoleInterp = info->consoleInterp; - Tcl_Preserve((ClientData) consoleInterp); - Tcl_Eval(consoleInterp, command.string); - Tcl_Release((ClientData) consoleInterp); - - Tcl_DStringFree(&command); - Tcl_DStringFree(&output); -} diff --git a/generic/tkCursor.c b/generic/tkCursor.c deleted file mode 100644 index 297cd3e..0000000 --- a/generic/tkCursor.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * tkCursor.c -- - * - * This file maintains a database of read-only cursors for the Tk - * toolkit. This allows cursors to be shared between widgets and - * also avoids round-trips to the X server. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkCursor.c,v 1.2 1998/09/14 18:23:09 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * A TkCursor structure exists for each cursor that is currently - * active. Each structure is indexed with two hash tables defined - * below. One of the tables is idTable, and the other is either - * nameTable or dataTable, also defined below. - */ - -/* - * Hash table to map from a textual description of a cursor to the - * TkCursor record for the cursor, and key structure used in that - * hash table: - */ - -static Tcl_HashTable nameTable; -typedef struct { - Tk_Uid name; /* Textual name for desired cursor. */ - Display *display; /* Display for which cursor will be used. */ -} NameKey; - -/* - * Hash table to map from a collection of in-core data about a - * cursor (bitmap contents, etc.) to a TkCursor structure: - */ - -static Tcl_HashTable dataTable; -typedef struct { - char *source; /* Cursor bits. */ - char *mask; /* Mask bits. */ - int width, height; /* Dimensions of cursor (and data - * and mask). */ - int xHot, yHot; /* Location of cursor hot-spot. */ - Tk_Uid fg, bg; /* Colors for cursor. */ - Display *display; /* Display on which cursor will be used. */ -} DataKey; - -/* - * Hash table that maps from <display + cursor id> to the TkCursor structure - * for the cursor. This table is used by Tk_FreeCursor. - */ - -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which cursor was allocated. */ - Tk_Cursor cursor; /* Cursor identifier. */ -} IdKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static void CursorInit _ANSI_ARGS_((void)); - -/* - *---------------------------------------------------------------------- - * - * Tk_GetCursor -- - * - * Given a string describing a cursor, locate (or create if necessary) - * a cursor that fits the description. - * - * Results: - * The return value is the X identifer for the desired cursor, - * unless string couldn't be parsed correctly. In this case, - * None is returned and an error message is left in interp->result. - * The caller should never modify the cursor that is returned, and - * should eventually call Tk_FreeCursor when the cursor is no longer - * needed. - * - * Side effects: - * The cursor is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeCursor, so that the database can be cleaned up when cursors - * aren't needed anymore. - * - *---------------------------------------------------------------------- - */ - -Tk_Cursor -Tk_GetCursor(interp, tkwin, string) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Window tkwin; /* Window in which cursor will be used. */ - Tk_Uid string; /* Description of cursor. See manual entry - * for details on legal syntax. */ -{ - NameKey nameKey; - IdKey idKey; - Tcl_HashEntry *nameHashPtr, *idHashPtr; - register TkCursor *cursorPtr; - int new; - - if (!initialized) { - CursorInit(); - } - - nameKey.name = string; - nameKey.display = Tk_Display(tkwin); - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); - if (!new) { - cursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr); - cursorPtr->refCount++; - return cursorPtr->cursor; - } - - cursorPtr = TkGetCursorByName(interp, tkwin, string); - - if (cursorPtr == NULL) { - Tcl_DeleteHashEntry(nameHashPtr); - return None; - } - - /* - * Add information about this cursor to our database. - */ - - cursorPtr->refCount = 1; - cursorPtr->otherTable = &nameTable; - cursorPtr->hashPtr = nameHashPtr; - idKey.display = nameKey.display; - idKey.cursor = cursorPtr->cursor; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); - if (!new) { - panic("cursor already registered in Tk_GetCursor"); - } - Tcl_SetHashValue(nameHashPtr, cursorPtr); - Tcl_SetHashValue(idHashPtr, cursorPtr); - - return cursorPtr->cursor; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetCursorFromData -- - * - * Given a description of the bits and colors for a cursor, - * make a cursor that has the given properties. - * - * Results: - * The return value is the X identifer for the desired cursor, - * unless it couldn't be created properly. In this case, None is - * returned and an error message is left in interp->result. The - * caller should never modify the cursor that is returned, and - * should eventually call Tk_FreeCursor when the cursor is no - * longer needed. - * - * Side effects: - * The cursor is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeCursor, so that the database can be cleaned up when cursors - * aren't needed anymore. - * - *---------------------------------------------------------------------- - */ - -Tk_Cursor -Tk_GetCursorFromData(interp, tkwin, source, mask, width, height, - xHot, yHot, fg, bg) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Window tkwin; /* Window in which cursor will be used. */ - char *source; /* Bitmap data for cursor shape. */ - char *mask; /* Bitmap data for cursor mask. */ - int width, height; /* Dimensions of cursor. */ - int xHot, yHot; /* Location of hot-spot in cursor. */ - Tk_Uid fg; /* Foreground color for cursor. */ - Tk_Uid bg; /* Background color for cursor. */ -{ - DataKey dataKey; - IdKey idKey; - Tcl_HashEntry *dataHashPtr, *idHashPtr; - register TkCursor *cursorPtr; - int new; - XColor fgColor, bgColor; - - if (!initialized) { - CursorInit(); - } - - dataKey.source = source; - dataKey.mask = mask; - dataKey.width = width; - dataKey.height = height; - dataKey.xHot = xHot; - dataKey.yHot = yHot; - dataKey.fg = fg; - dataKey.bg = bg; - dataKey.display = Tk_Display(tkwin); - dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &dataKey, &new); - if (!new) { - cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr); - cursorPtr->refCount++; - return cursorPtr->cursor; - } - - /* - * No suitable cursor exists yet. Make one using the data - * available and add it to the database. - */ - - if (XParseColor(dataKey.display, Tk_Colormap(tkwin), fg, &fgColor) == 0) { - Tcl_AppendResult(interp, "invalid color name \"", fg, "\"", - (char *) NULL); - goto error; - } - if (XParseColor(dataKey.display, Tk_Colormap(tkwin), bg, &bgColor) == 0) { - Tcl_AppendResult(interp, "invalid color name \"", bg, "\"", - (char *) NULL); - goto error; - } - - cursorPtr = TkCreateCursorFromData(tkwin, source, mask, width, height, - xHot, yHot, fgColor, bgColor); - - if (cursorPtr == NULL) { - goto error; - } - - cursorPtr->refCount = 1; - cursorPtr->otherTable = &dataTable; - cursorPtr->hashPtr = dataHashPtr; - idKey.display = dataKey.display; - idKey.cursor = cursorPtr->cursor; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); - if (!new) { - panic("cursor already registered in Tk_GetCursorFromData"); - } - Tcl_SetHashValue(dataHashPtr, cursorPtr); - Tcl_SetHashValue(idHashPtr, cursorPtr); - return cursorPtr->cursor; - - error: - Tcl_DeleteHashEntry(dataHashPtr); - return None; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfCursor -- - * - * Given a cursor, return a textual string identifying it. - * - * Results: - * If cursor was created by Tk_GetCursor, then the return - * value is the "string" that was used to create it. - * Otherwise the return value is a string giving the X - * identifier for the cursor. The storage for the returned - * string is only guaranteed to persist up until the next - * call to this procedure. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfCursor(display, cursor) - Display *display; /* Display for which cursor was allocated. */ - Tk_Cursor cursor; /* Identifier for cursor whose name is - * wanted. */ -{ - IdKey idKey; - Tcl_HashEntry *idHashPtr; - TkCursor *cursorPtr; - static char string[20]; - - if (!initialized) { - printid: - sprintf(string, "cursor id 0x%x", (unsigned int) cursor); - return string; - } - idKey.display = display; - idKey.cursor = cursor; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - goto printid; - } - cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr); - if (cursorPtr->otherTable != &nameTable) { - goto printid; - } - return ((NameKey *) cursorPtr->hashPtr->key.words)->name; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeCursor -- - * - * This procedure is called to release a cursor allocated by - * Tk_GetCursor or TkGetCursorFromData. - * - * Results: - * None. - * - * Side effects: - * The reference count associated with cursor is decremented, and - * it is officially deallocated if no-one is using it anymore. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeCursor(display, cursor) - Display *display; /* Display for which cursor was allocated. */ - Tk_Cursor cursor; /* Identifier for cursor to be released. */ -{ - IdKey idKey; - Tcl_HashEntry *idHashPtr; - register TkCursor *cursorPtr; - - if (!initialized) { - panic("Tk_FreeCursor called before Tk_GetCursor"); - } - - idKey.display = display; - idKey.cursor = cursor; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - panic("Tk_FreeCursor received unknown cursor argument"); - } - cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr); - cursorPtr->refCount--; - if (cursorPtr->refCount == 0) { - Tcl_DeleteHashEntry(cursorPtr->hashPtr); - Tcl_DeleteHashEntry(idHashPtr); - TkFreeCursor(cursorPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * CursorInit -- - * - * Initialize the structures used for cursor management. - * - * Results: - * None. - * - * Side effects: - * Read the code. - * - *---------------------------------------------------------------------- - */ - -static void -CursorInit() -{ - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); - - /* - * The call below is tricky: can't use sizeof(IdKey) because it - * gets padded with extra unpredictable bytes on some 64-bit - * machines. - */ - - Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Tk_Cursor)) - /sizeof(int)); -} diff --git a/generic/tkEntry.c b/generic/tkEntry.c deleted file mode 100644 index 9dc65ee..0000000 --- a/generic/tkEntry.c +++ /dev/null @@ -1,2313 +0,0 @@ -/* - * tkEntry.c -- - * - * This module implements entry widgets for the Tk - * toolkit. An entry displays a string and allows - * the string to be edited. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkEntry.c,v 1.2 1998/09/14 18:23:09 stanton Exp $ - */ - -#include "tkInt.h" -#include "default.h" - -/* - * A data structure of the following type is kept for each entry - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the entry. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with entry. */ - Tcl_Command widgetCmd; /* Token for entry's widget command. */ - - /* - * Fields that are set by widget commands other than "configure". - */ - - char *string; /* Pointer to storage for string; - * NULL-terminated; malloc-ed. */ - int insertPos; /* Index of character before which next - * typed character will be inserted. */ - - /* - * Information about what's selected, if any. - */ - - int selectFirst; /* Index of first selected character (-1 means - * nothing selected. */ - int selectLast; /* Index of last selected character (-1 means - * nothing selected. */ - int selectAnchor; /* Fixed end of selection (i.e. "select to" - * operation will use this as one end of the - * selection). */ - - /* - * Information for scanning: - */ - - int scanMarkX; /* X-position at which scan started (e.g. - * button was pressed here). */ - int scanMarkIndex; /* Index of character that was at left of - * window when scan started. */ - - /* - * Configuration settings that are updated by Tk_ConfigureWidget. - */ - - Tk_3DBorder normalBorder; /* Used for drawing border around whole - * window, plus used for background. */ - int borderWidth; /* Width of 3-D border around window. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - int exportSelection; /* Non-zero means tie internal entry selection - * to X selection. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *fgColorPtr; /* Text color in normal mode. */ - XColor *highlightBgColorPtr;/* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion - * cursor. */ - int insertBorderWidth; /* Width of 3-D border around insert cursor. */ - int insertOffTime; /* Number of milliseconds cursor should spend - * in "off" state for each blink. */ - int insertOnTime; /* Number of milliseconds cursor should spend - * in "on" state for each blink. */ - int insertWidth; /* Total width of insert cursor. */ - Tk_Justify justify; /* Justification to use for text within - * window. */ - int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */ - Tk_3DBorder selBorder; /* Border and background for selected - * characters. */ - int selBorderWidth; /* Width of border around selection. */ - XColor *selFgColorPtr; /* Foreground color for selected text. */ - char *showChar; /* Value of -show option. If non-NULL, first - * character is used for displaying all - * characters in entry. Malloc'ed. */ - Tk_Uid state; /* Normal or disabled. Entry is read-only - * when disabled. */ - char *textVarName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, entry's string tracks the - * contents of this variable and vice versa. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int prefWidth; /* Desired width of window, measured in - * average characters. */ - char *scrollCmd; /* Command prefix for communicating with - * scrollbar(s). Malloc'ed. NULL means - * no command to issue. */ - - /* - * Fields whose values are derived from the current values of the - * configuration settings above. - */ - - int numChars; /* Number of non-NULL characters in - * string (may be 0). */ - char *displayString; /* If non-NULL, points to string with same - * length as string but whose characters - * are all equal to showChar. Malloc'ed. */ - int inset; /* Number of pixels on the left and right - * sides that are taken up by XPAD, borderWidth - * (if any), and highlightWidth (if any). */ - Tk_TextLayout textLayout; /* Cached text layout information. */ - int layoutX, layoutY; /* Origin for layout. */ - int leftIndex; /* Index of left-most character visible in - * window. */ - int leftX; /* X position at which character at leftIndex - * is drawn (varies depending on justify). */ - Tcl_TimerToken insertBlinkHandler; - /* Timer handler used to blink cursor on and - * off. */ - GC textGC; /* For drawing normal text. */ - GC selTextGC; /* For drawing selected text. */ - GC highlightGC; /* For drawing traversal highlight. */ - int avgWidth; /* Width of average character. */ - int flags; /* Miscellaneous flags; see below for - * definitions. */ -} Entry; - -/* - * Assigned bits of "flags" fields of Entry structures, and what those - * bits mean: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has - * already been queued to redisplay the entry. - * BORDER_NEEDED: Non-zero means 3-D border must be redrawn - * around window during redisplay. Normally - * only text portion needs to be redrawn. - * CURSOR_ON: Non-zero means insert cursor is displayed at - * present. 0 means it isn't displayed. - * GOT_FOCUS: Non-zero means this window has the input - * focus. - * UPDATE_SCROLLBAR: Non-zero means scrollbar should be updated - * during next redisplay operation. - * GOT_SELECTION: Non-zero means we've claimed the selection. - */ - -#define REDRAW_PENDING 1 -#define BORDER_NEEDED 2 -#define CURSOR_ON 4 -#define GOT_FOCUS 8 -#define UPDATE_SCROLLBAR 0x10 -#define GOT_SELECTION 0x20 - -/* - * The following macro defines how many extra pixels to leave on each - * side of the text in the entry. - */ - -#define XPAD 1 -#define YPAD 1 - -/* - * Information used for argv parsing. - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_ENTRY_BG_COLOR, Tk_Offset(Entry, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_ENTRY_BG_MONO, Tk_Offset(Entry, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_ENTRY_BORDER_WIDTH, Tk_Offset(Entry, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_ENTRY_CURSOR, Tk_Offset(Entry, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, - Tk_Offset(Entry, exportSelection), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_ENTRY_FONT, Tk_Offset(Entry, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_ENTRY_FG, Tk_Offset(Entry, fgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG, - Tk_Offset(Entry, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_ENTRY_HIGHLIGHT, Tk_Offset(Entry, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_ENTRY_HIGHLIGHT_WIDTH, Tk_Offset(Entry, highlightWidth), 0}, - {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground", - DEF_ENTRY_INSERT_BG, Tk_Offset(Entry, insertBorder), 0}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_ENTRY_INSERT_BD_COLOR, Tk_Offset(Entry, insertBorderWidth), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_ENTRY_INSERT_BD_MONO, Tk_Offset(Entry, insertBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", - DEF_ENTRY_INSERT_OFF_TIME, Tk_Offset(Entry, insertOffTime), 0}, - {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", - DEF_ENTRY_INSERT_ON_TIME, Tk_Offset(Entry, insertOnTime), 0}, - {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", - DEF_ENTRY_INSERT_WIDTH, Tk_Offset(Entry, insertWidth), 0}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_ENTRY_JUSTIFY, Tk_Offset(Entry, justify), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_ENTRY_RELIEF, Tk_Offset(Entry, relief), 0}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_ENTRY_SELECT_COLOR, Tk_Offset(Entry, selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_ENTRY_SELECT_MONO, Tk_Offset(Entry, selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_ENTRY_SELECT_BD_COLOR, Tk_Offset(Entry, selBorderWidth), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_ENTRY_SELECT_BD_MONO, Tk_Offset(Entry, selBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_ENTRY_SELECT_FG_COLOR, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_ENTRY_SELECT_FG_MONO, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-show", "show", "Show", - DEF_ENTRY_SHOW, Tk_Offset(Entry, showChar), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_ENTRY_STATE, Tk_Offset(Entry, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_ENTRY_TAKE_FOCUS, Tk_Offset(Entry, takeFocus), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_ENTRY_TEXT_VARIABLE, Tk_Offset(Entry, textVarName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-width", "width", "Width", - DEF_ENTRY_WIDTH, Tk_Offset(Entry, prefWidth), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_ENTRY_SCROLL_COMMAND, Tk_Offset(Entry, scrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Flags for GetEntryIndex procedure: - */ - -#define ZERO_OK 1 -#define LAST_PLUS_ONE_OK 2 - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp, - Entry *entryPtr, int argc, char **argv, - int flags)); -static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index, - int count)); -static void DestroyEntry _ANSI_ARGS_((char *memPtr)); -static void DisplayEntry _ANSI_ARGS_((ClientData clientData)); -static void EntryBlinkProc _ANSI_ARGS_((ClientData clientData)); -static void EntryCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr)); -static void EntryEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr, - int gotFocus)); -static int EntryFetchSelection _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static void EntryLostSelection _ANSI_ARGS_(( - ClientData clientData)); -static void EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr)); -static void EntryScanTo _ANSI_ARGS_((Entry *entryPtr, int y)); -static void EntrySetValue _ANSI_ARGS_((Entry *entryPtr, - char *value)); -static void EntrySelectTo _ANSI_ARGS_(( - Entry *entryPtr, int index)); -static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr)); -static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr)); -static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr, - double *firstPtr, double *lastPtr)); -static int EntryWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void EntryWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp, - Entry *entryPtr, char *string, int *indexPtr)); -static void InsertChars _ANSI_ARGS_((Entry *entryPtr, int index, - char *string)); - -/* - * The structure below defines entry class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs entryClass = { - NULL, /* createProc. */ - EntryWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_EntryCmd -- - * - * This procedure is invoked to process the "entry" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_EntryCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - register Entry *entryPtr; - Tk_Window new; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - /* - * Initialize the fields of the structure that won't be initialized - * by ConfigureEntry, or that ConfigureEntry requires to be - * initialized already (e.g. resource pointers). - */ - - entryPtr = (Entry *) ckalloc(sizeof(Entry)); - entryPtr->tkwin = new; - entryPtr->display = Tk_Display(new); - entryPtr->interp = interp; - entryPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(entryPtr->tkwin), EntryWidgetCmd, - (ClientData) entryPtr, EntryCmdDeletedProc); - entryPtr->string = (char *) ckalloc(1); - entryPtr->string[0] = '\0'; - entryPtr->insertPos = 0; - entryPtr->selectFirst = -1; - entryPtr->selectLast = -1; - entryPtr->selectAnchor = 0; - entryPtr->scanMarkX = 0; - entryPtr->scanMarkIndex = 0; - - entryPtr->normalBorder = NULL; - entryPtr->borderWidth = 0; - entryPtr->cursor = None; - entryPtr->exportSelection = 1; - entryPtr->tkfont = NULL; - entryPtr->fgColorPtr = NULL; - entryPtr->highlightBgColorPtr = NULL; - entryPtr->highlightColorPtr = NULL; - entryPtr->highlightWidth = 0; - entryPtr->insertBorder = NULL; - entryPtr->insertBorderWidth = 0; - entryPtr->insertOffTime = 0; - entryPtr->insertOnTime = 0; - entryPtr->insertWidth = 0; - entryPtr->justify = TK_JUSTIFY_LEFT; - entryPtr->relief = TK_RELIEF_FLAT; - entryPtr->selBorder = NULL; - entryPtr->selBorderWidth = 0; - entryPtr->selFgColorPtr = NULL; - entryPtr->showChar = NULL; - entryPtr->state = tkNormalUid; - entryPtr->textVarName = NULL; - entryPtr->takeFocus = NULL; - entryPtr->prefWidth = 0; - entryPtr->scrollCmd = NULL; - - entryPtr->numChars = 0; - entryPtr->displayString = NULL; - entryPtr->inset = XPAD; - entryPtr->textLayout = NULL; - entryPtr->layoutX = 0; - entryPtr->layoutY = 0; - entryPtr->leftIndex = 0; - entryPtr->leftX = 0; - entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - entryPtr->textGC = None; - entryPtr->selTextGC = None; - entryPtr->highlightGC = None; - entryPtr->avgWidth = 1; - entryPtr->flags = 0; - - Tk_SetClass(entryPtr->tkwin, "Entry"); - TkSetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr); - Tk_CreateEventHandler(entryPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - EntryEventProc, (ClientData) entryPtr); - Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING, - EntryFetchSelection, (ClientData) entryPtr, XA_STRING); - if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - interp->result = Tk_PathName(entryPtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(entryPtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * EntryWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -EntryWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about entry widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Entry *entryPtr = (Entry *) clientData; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) entryPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - int index; - int x, y, width, height; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox index\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - if ((index == entryPtr->numChars) && (index > 0)) { - index--; - } - Tk_CharBbox(entryPtr->textLayout, index, &x, &y, &width, &height); - sprintf(interp->result, "%d %d %d %d", - x + entryPtr->layoutX, y + entryPtr->layoutY, width, height); - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, argv[2], 0); - } else { - result = ConfigureEntry(interp, entryPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; - - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete firstIndex ?lastIndex?\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) { - goto error; - } - if (argc == 3) { - last = first+1; - } else { - if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) { - goto error; - } - } - if ((last >= first) && (entryPtr->state == tkNormalUid)) { - DeleteChars(entryPtr, first, last-first); - } - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get\"", (char *) NULL); - goto error; - } - interp->result = entryPtr->string; - } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " icursor pos\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->insertPos) - != TCL_OK) { - goto error; - } - EventuallyRedraw(entryPtr); - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index string\"", (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index text\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - if (entryPtr->state == tkNormalUid) { - InsertChars(entryPtr, index, argv[3]); - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "scan", length) == 0)) { - int x; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x\"", (char *) NULL); - goto error; - } - if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) { - goto error; - } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { - entryPtr->scanMarkX = x; - entryPtr->scanMarkIndex = entryPtr->leftIndex; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { - EntryScanTo(entryPtr, x); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "selection", length) == 0)) { - int index, index2; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select option ?index?\"", (char *) NULL); - goto error; - } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection clear\"", (char *) NULL); - goto error; - } - if (entryPtr->selectFirst != -1) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - EventuallyRedraw(entryPtr); - } - goto done; - } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection present\"", (char *) NULL); - goto error; - } - if (entryPtr->selectFirst == -1) { - interp->result = "0"; - } else { - interp->result = "1"; - } - goto done; - } - if (argc >= 4) { - if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) { - goto error; - } - } - if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection adjust index\"", - (char *) NULL); - goto error; - } - if (entryPtr->selectFirst >= 0) { - int half1, half2; - - half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2; - half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2; - if (index < half1) { - entryPtr->selectAnchor = entryPtr->selectLast; - } else if (index > half2) { - entryPtr->selectAnchor = entryPtr->selectFirst; - } else { - /* - * We're at about the halfway point in the selection; - * just keep the existing anchor. - */ - } - } - EntrySelectTo(entryPtr, index); - } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection from index\"", - (char *) NULL); - goto error; - } - entryPtr->selectAnchor = index; - } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection range start end\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[4], &index2) != TCL_OK) { - goto error; - } - if (index >= index2) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - } else { - entryPtr->selectFirst = index; - entryPtr->selectLast = index2; - } - if (!(entryPtr->flags & GOT_SELECTION) - && (entryPtr->exportSelection)) { - Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, - EntryLostSelection, (ClientData) entryPtr); - entryPtr->flags |= GOT_SELECTION; - } - EventuallyRedraw(entryPtr); - } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection to index\"", - (char *) NULL); - goto error; - } - EntrySelectTo(entryPtr, index); - } else { - Tcl_AppendResult(interp, "bad selection option \"", argv[2], - "\": must be adjust, clear, from, present, range, or to", - (char *) NULL); - goto error; - } - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - int index, type, count, charsPerPage; - double fraction, first, last; - - if (argc == 2) { - EntryVisibleRange(entryPtr, &first, &last); - sprintf(interp->result, "%g %g", first, last); - goto done; - } else if (argc == 3) { - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - index = entryPtr->leftIndex; - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - index = (int) ((fraction * entryPtr->numChars) + 0.5); - break; - case TK_SCROLL_PAGES: - charsPerPage = ((Tk_Width(entryPtr->tkwin) - - 2*entryPtr->inset) / entryPtr->avgWidth) - 2; - if (charsPerPage < 1) { - charsPerPage = 1; - } - index += charsPerPage*count; - break; - case TK_SCROLL_UNITS: - index += count; - break; - } - } - if (index >= entryPtr->numChars) { - index = entryPtr->numChars-1; - } - if (index < 0) { - index = 0; - } - entryPtr->leftIndex = index; - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be bbox, cget, configure, delete, get, ", - "icursor, index, insert, scan, selection, or xview", - (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) entryPtr); - return result; - - error: - Tcl_Release((ClientData) entryPtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyEntry -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of an entry at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the entry is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyEntry(memPtr) - char *memPtr; /* Info about entry widget. */ -{ - register Entry *entryPtr = (Entry *) memPtr; - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - ckfree(entryPtr->string); - if (entryPtr->textVarName != NULL) { - Tcl_UntraceVar(entryPtr->interp, entryPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - EntryTextVarProc, (ClientData) entryPtr); - } - if (entryPtr->textGC != None) { - Tk_FreeGC(entryPtr->display, entryPtr->textGC); - } - if (entryPtr->selTextGC != None) { - Tk_FreeGC(entryPtr->display, entryPtr->selTextGC); - } - Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler); - if (entryPtr->displayString != NULL) { - ckfree(entryPtr->displayString); - } - Tk_FreeTextLayout(entryPtr->textLayout); - Tk_FreeOptions(configSpecs, (char *) entryPtr, entryPtr->display, 0); - ckfree((char *) entryPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureEntry -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or reconfigure) - * an entry widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for entryPtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureEntry(interp, entryPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register Entry *entryPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - int oldExport; - - /* - * Eliminate any existing trace on a variable monitored by the entry. - */ - - if (entryPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, entryPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - EntryTextVarProc, (ClientData) entryPtr); - } - - oldExport = entryPtr->exportSelection; - if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs, - argc, argv, (char *) entryPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * If the entry is tied to the value of a variable, then set up - * a trace on the variable's value, create the variable if it doesn't - * exist, and set the entry's value from the variable's value. - */ - - if (entryPtr->textVarName != NULL) { - char *value; - - value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - EntryValueChanged(entryPtr); - } else { - EntrySetValue(entryPtr, value); - } - Tcl_TraceVar(interp, entryPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - EntryTextVarProc, (ClientData) entryPtr); - } - - /* - * A few other options also need special processing, such as parsing - * the geometry and setting the background from a 3-D border. - */ - - if ((entryPtr->state != tkNormalUid) - && (entryPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", entryPtr->state, - "\": must be normal or disabled", (char *) NULL); - entryPtr->state = tkNormalUid; - return TCL_ERROR; - } - - Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); - - if (entryPtr->insertWidth <= 0) { - entryPtr->insertWidth = 2; - } - if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) { - entryPtr->insertBorderWidth = entryPtr->insertWidth/2; - } - - /* - * Restart the cursor timing sequence in case the on-time or off-time - * just changed. - */ - - if (entryPtr->flags & GOT_FOCUS) { - EntryFocusProc(entryPtr, 1); - } - - /* - * Claim the selection if we've suddenly started exporting it. - */ - - if (entryPtr->exportSelection && (!oldExport) - && (entryPtr->selectFirst != -1) - && !(entryPtr->flags & GOT_SELECTION)) { - Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection, - (ClientData) entryPtr); - entryPtr->flags |= GOT_SELECTION; - } - - /* - * Recompute the window's geometry and arrange for it to be - * redisplayed. - */ - - Tk_SetInternalBorder(entryPtr->tkwin, - entryPtr->borderWidth + entryPtr->highlightWidth); - if (entryPtr->highlightWidth <= 0) { - entryPtr->highlightWidth = 0; - } - entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD; - - EntryWorldChanged((ClientData) entryPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * EntryWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Entry will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -EntryWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC gc; - unsigned long mask; - Entry *entryPtr; - - entryPtr = (Entry *) instanceData; - - entryPtr->avgWidth = Tk_TextWidth(entryPtr->tkfont, "0", 1); - if (entryPtr->avgWidth == 0) { - entryPtr->avgWidth = 1; - } - - gcValues.foreground = entryPtr->fgColorPtr->pixel; - gcValues.font = Tk_FontId(entryPtr->tkfont); - gcValues.graphics_exposures = False; - mask = GCForeground | GCFont | GCGraphicsExposures; - gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); - if (entryPtr->textGC != None) { - Tk_FreeGC(entryPtr->display, entryPtr->textGC); - } - entryPtr->textGC = gc; - - gcValues.foreground = entryPtr->selFgColorPtr->pixel; - gcValues.font = Tk_FontId(entryPtr->tkfont); - mask = GCForeground | GCFont; - gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); - if (entryPtr->selTextGC != None) { - Tk_FreeGC(entryPtr->display, entryPtr->selTextGC); - } - entryPtr->selTextGC = gc; - - /* - * Recompute the window's geometry and arrange for it to be - * redisplayed. - */ - - EntryComputeGeometry(entryPtr); - entryPtr->flags |= UPDATE_SCROLLBAR; - EventuallyRedraw(entryPtr); -} - -/* - *-------------------------------------------------------------- - * - * DisplayEntry -- - * - * This procedure redraws the contents of an entry window. - * - * Results: - * None. - * - * Side effects: - * Information appears on the screen. - * - *-------------------------------------------------------------- - */ - -static void -DisplayEntry(clientData) - ClientData clientData; /* Information about window. */ -{ - register Entry *entryPtr = (Entry *) clientData; - register Tk_Window tkwin = entryPtr->tkwin; - int baseY, selStartX, selEndX, cursorX, x, w; - int xBound; - Tk_FontMetrics fm; - Pixmap pixmap; - int showSelection; - - entryPtr->flags &= ~REDRAW_PENDING; - if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { - return; - } - - Tk_GetFontMetrics(entryPtr->tkfont, &fm); - - /* - * Update the scrollbar if that's needed. - */ - - if (entryPtr->flags & UPDATE_SCROLLBAR) { - entryPtr->flags &= ~UPDATE_SCROLLBAR; - EntryUpdateScrollbar(entryPtr); - } - - /* - * In order to avoid screen flashes, this procedure redraws the - * textual area of the entry into off-screen memory, then copies - * it back on-screen in a single operation. This means there's - * no point in time where the on-screen image has been cleared. - */ - - pixmap = Tk_GetPixmap(entryPtr->display, Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); - - /* - * Compute x-coordinate of the pixel just after last visible - * one, plus vertical position of baseline of text. - */ - - xBound = Tk_Width(tkwin) - entryPtr->inset; - baseY = (Tk_Height(tkwin) + fm.ascent - fm.descent) / 2; - - /* - * On Windows and Mac, we need to hide the selection whenever we - * don't have the focus. - */ - -#ifdef ALWAYS_SHOW_SELECTION - showSelection = 1; -#else - showSelection = (entryPtr->flags & GOT_FOCUS); -#endif - - /* - * Draw the background in three layers. From bottom to top the - * layers are: normal background, selection background, and - * insertion cursor background. - */ - - Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - if (showSelection && (entryPtr->selectLast > entryPtr->leftIndex)) { - if (entryPtr->selectFirst <= entryPtr->leftIndex) { - selStartX = entryPtr->leftX; - } else { - Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst, - &x, NULL, NULL, NULL); - selStartX = x + entryPtr->layoutX; - } - if ((selStartX - entryPtr->selBorderWidth) < xBound) { - Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast - 1, - &x, NULL, &w, NULL); - selEndX = x + w + entryPtr->layoutX; - Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder, - selStartX - entryPtr->selBorderWidth, - baseY - fm.ascent - entryPtr->selBorderWidth, - (selEndX - selStartX) + 2*entryPtr->selBorderWidth, - (fm.ascent + fm.descent) + 2*entryPtr->selBorderWidth, - entryPtr->selBorderWidth, TK_RELIEF_RAISED); - } - } - - /* - * Draw a special background for the insertion cursor, overriding - * even the selection background. As a special hack to keep the - * cursor visible when the insertion cursor color is the same as - * the color for selected text (e.g., on mono displays), write - * background in the cursor area (instead of nothing) when the - * cursor isn't on. Otherwise the selection would hide the cursor. - */ - - if ((entryPtr->insertPos >= entryPtr->leftIndex) - && (entryPtr->state == tkNormalUid) - && (entryPtr->flags & GOT_FOCUS)) { - if (entryPtr->insertPos == 0) { - cursorX = 0; - } else if (entryPtr->insertPos >= entryPtr->numChars) { - Tk_CharBbox(entryPtr->textLayout, entryPtr->numChars - 1, - &x, NULL, &w, NULL); - cursorX = x + w; - } else { - Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, - &x, NULL, NULL, NULL); - cursorX = x; - } - cursorX += entryPtr->layoutX; - cursorX -= (entryPtr->insertWidth)/2; - if (cursorX < xBound) { - if (entryPtr->flags & CURSOR_ON) { - Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder, - cursorX, baseY - fm.ascent, - entryPtr->insertWidth, fm.ascent + fm.descent, - entryPtr->insertBorderWidth, TK_RELIEF_RAISED); - } else if (entryPtr->insertBorder == entryPtr->selBorder) { - Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - cursorX, baseY - fm.ascent, - entryPtr->insertWidth, fm.ascent + fm.descent, - 0, TK_RELIEF_FLAT); - } - } - } - - /* - * Draw the text in two pieces: first the unselected portion, then the - * selected portion on top of it. - */ - - Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, - entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, - entryPtr->leftIndex, entryPtr->numChars); - - if (showSelection && (entryPtr->selTextGC != entryPtr->textGC) && - (entryPtr->selectFirst < entryPtr->selectLast)) { - int first; - - if (entryPtr->selectFirst - entryPtr->leftIndex < 0) { - first = entryPtr->leftIndex; - } else { - first = entryPtr->selectFirst; - } - Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC, - entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, - first, entryPtr->selectLast); - } - - /* - * Draw the border and focus highlight last, so they will overwrite - * any text that extends past the viewable part of the window. - */ - - if (entryPtr->relief != TK_RELIEF_FLAT) { - Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - entryPtr->highlightWidth, entryPtr->highlightWidth, - Tk_Width(tkwin) - 2*entryPtr->highlightWidth, - Tk_Height(tkwin) - 2*entryPtr->highlightWidth, - entryPtr->borderWidth, entryPtr->relief); - } - if (entryPtr->highlightWidth != 0) { - GC gc; - - if (entryPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap); - } else { - gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap); - } - Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap); - } - - /* - * Everything's been redisplayed; now copy the pixmap onto the screen - * and free up the pixmap. - */ - - XCopyArea(entryPtr->display, pixmap, Tk_WindowId(tkwin), entryPtr->textGC, - 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), - 0, 0); - Tk_FreePixmap(entryPtr->display, pixmap); - entryPtr->flags &= ~BORDER_NEEDED; -} - -/* - *---------------------------------------------------------------------- - * - * EntryComputeGeometry -- - * - * This procedure is invoked to recompute information about where - * in its window an entry's string will be displayed. It also - * computes the requested size for the window. - * - * Results: - * None. - * - * Side effects: - * The leftX and tabOrigin fields are recomputed for entryPtr, - * and leftIndex may be adjusted. Tk_GeometryRequest is called - * to register the desired dimensions for the window. - * - *---------------------------------------------------------------------- - */ - -static void -EntryComputeGeometry(entryPtr) - Entry *entryPtr; /* Widget record for entry. */ -{ - int totalLength, overflow, maxOffScreen, rightX; - int height, width, i; - Tk_FontMetrics fm; - char *p, *displayString; - - /* - * If we're displaying a special character instead of the value of - * the entry, recompute the displayString. - */ - - if (entryPtr->displayString != NULL) { - ckfree(entryPtr->displayString); - entryPtr->displayString = NULL; - } - if (entryPtr->showChar != NULL) { - entryPtr->displayString = (char *) ckalloc((unsigned) - (entryPtr->numChars + 1)); - for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0; - i--, p++) { - *p = entryPtr->showChar[0]; - } - *p = 0; - displayString = entryPtr->displayString; - } else { - displayString = entryPtr->string; - } - Tk_FreeTextLayout(entryPtr->textLayout); - entryPtr->textLayout = Tk_ComputeTextLayout(entryPtr->tkfont, - displayString, entryPtr->numChars, 0, entryPtr->justify, - TK_IGNORE_NEWLINES, &totalLength, &height); - - entryPtr->layoutY = (Tk_Height(entryPtr->tkwin) - height) / 2; - - /* - * Recompute where the leftmost character on the display will - * be drawn (entryPtr->leftX) and adjust leftIndex if necessary - * so that we don't let characters hang off the edge of the - * window unless the entire window is full. - */ - - overflow = totalLength - (Tk_Width(entryPtr->tkwin) - 2*entryPtr->inset); - if (overflow <= 0) { - entryPtr->leftIndex = 0; - if (entryPtr->justify == TK_JUSTIFY_LEFT) { - entryPtr->leftX = entryPtr->inset; - } else if (entryPtr->justify == TK_JUSTIFY_RIGHT) { - entryPtr->leftX = Tk_Width(entryPtr->tkwin) - entryPtr->inset - - totalLength; - } else { - entryPtr->leftX = (Tk_Width(entryPtr->tkwin) - totalLength)/2; - } - entryPtr->layoutX = entryPtr->leftX; - } else { - /* - * The whole string can't fit in the window. Compute the - * maximum number of characters that may be off-screen to - * the left without leaving empty space on the right of the - * window, then don't let leftIndex be any greater than that. - */ - - maxOffScreen = Tk_PointToChar(entryPtr->textLayout, overflow, 0); - Tk_CharBbox(entryPtr->textLayout, maxOffScreen, - &rightX, NULL, NULL, NULL); - if (rightX < overflow) { - maxOffScreen += 1; - } - if (entryPtr->leftIndex > maxOffScreen) { - entryPtr->leftIndex = maxOffScreen; - } - Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, - &rightX, NULL, NULL, NULL); - entryPtr->leftX = entryPtr->inset; - entryPtr->layoutX = entryPtr->leftX - rightX; - } - - Tk_GetFontMetrics(entryPtr->tkfont, &fm); - height = fm.linespace + 2*entryPtr->inset + 2*(YPAD-XPAD); - if (entryPtr->prefWidth > 0) { - width = entryPtr->prefWidth*entryPtr->avgWidth + 2*entryPtr->inset; - } else { - if (totalLength == 0) { - width = entryPtr->avgWidth + 2*entryPtr->inset; - } else { - width = totalLength + 2*entryPtr->inset; - } - } - Tk_GeometryRequest(entryPtr->tkwin, width, height); -} - -/* - *---------------------------------------------------------------------- - * - * InsertChars -- - * - * Add new characters to an entry widget. - * - * Results: - * None. - * - * Side effects: - * New information gets added to entryPtr; it will be redisplayed - * soon, but not necessarily immediately. - * - *---------------------------------------------------------------------- - */ - -static void -InsertChars(entryPtr, index, string) - register Entry *entryPtr; /* Entry that is to get the new - * elements. */ - int index; /* Add the new elements before this - * element. */ - char *string; /* New characters to add (NULL-terminated - * string). */ -{ - int length; - char *new; - - length = strlen(string); - if (length == 0) { - return; - } - new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1)); - strncpy(new, entryPtr->string, (size_t) index); - strcpy(new+index, string); - strcpy(new+index+length, entryPtr->string+index); - ckfree(entryPtr->string); - entryPtr->string = new; - entryPtr->numChars += length; - - /* - * Inserting characters invalidates all indexes into the string. - * Touch up the indexes so that they still refer to the same - * characters (at new positions). When updating the selection - * end-points, don't include the new text in the selection unless - * it was completely surrounded by the selection. - */ - - if (entryPtr->selectFirst >= index) { - entryPtr->selectFirst += length; - } - if (entryPtr->selectLast > index) { - entryPtr->selectLast += length; - } - if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) { - entryPtr->selectAnchor += length; - } - if (entryPtr->leftIndex > index) { - entryPtr->leftIndex += length; - } - if (entryPtr->insertPos >= index) { - entryPtr->insertPos += length; - } - EntryValueChanged(entryPtr); -} - -/* - *---------------------------------------------------------------------- - * - * DeleteChars -- - * - * Remove one or more characters from an entry widget. - * - * Results: - * None. - * - * Side effects: - * Memory gets freed, the entry gets modified and (eventually) - * redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteChars(entryPtr, index, count) - register Entry *entryPtr; /* Entry widget to modify. */ - int index; /* Index of first character to delete. */ - int count; /* How many characters to delete. */ -{ - char *new; - - if ((index + count) > entryPtr->numChars) { - count = entryPtr->numChars - index; - } - if (count <= 0) { - return; - } - - new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count)); - strncpy(new, entryPtr->string, (size_t) index); - strcpy(new+index, entryPtr->string+index+count); - ckfree(entryPtr->string); - entryPtr->string = new; - entryPtr->numChars -= count; - - /* - * Deleting characters results in the remaining characters being - * renumbered. Update the various indexes into the string to reflect - * this change. - */ - - if (entryPtr->selectFirst >= index) { - if (entryPtr->selectFirst >= (index+count)) { - entryPtr->selectFirst -= count; - } else { - entryPtr->selectFirst = index; - } - } - if (entryPtr->selectLast >= index) { - if (entryPtr->selectLast >= (index+count)) { - entryPtr->selectLast -= count; - } else { - entryPtr->selectLast = index; - } - } - if (entryPtr->selectLast <= entryPtr->selectFirst) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - } - if (entryPtr->selectAnchor >= index) { - if (entryPtr->selectAnchor >= (index+count)) { - entryPtr->selectAnchor -= count; - } else { - entryPtr->selectAnchor = index; - } - } - if (entryPtr->leftIndex > index) { - if (entryPtr->leftIndex >= (index+count)) { - entryPtr->leftIndex -= count; - } else { - entryPtr->leftIndex = index; - } - } - if (entryPtr->insertPos >= index) { - if (entryPtr->insertPos >= (index+count)) { - entryPtr->insertPos -= count; - } else { - entryPtr->insertPos = index; - } - } - EntryValueChanged(entryPtr); -} - -/* - *---------------------------------------------------------------------- - * - * EntryValueChanged -- - * - * This procedure is invoked when characters are inserted into - * an entry or deleted from it. It updates the entry's associated - * variable, if there is one, and does other bookkeeping such - * as arranging for redisplay. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -EntryValueChanged(entryPtr) - Entry *entryPtr; /* Entry whose value just changed. */ -{ - char *newValue; - - if (entryPtr->textVarName == NULL) { - newValue = NULL; - } else { - newValue = Tcl_SetVar(entryPtr->interp, entryPtr->textVarName, - entryPtr->string, TCL_GLOBAL_ONLY); - } - - if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) { - /* - * The value of the variable is different than what we asked for. - * This means that a trace on the variable modified it. In this - * case our trace procedure wasn't invoked since the modification - * came while a trace was already active on the variable. So, - * update our value to reflect the variable's latest value. - */ - - EntrySetValue(entryPtr, newValue); - } else { - /* - * Arrange for redisplay. - */ - - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * EntrySetValue -- - * - * Replace the contents of a text entry with a given value. This - * procedure is invoked when updating the entry from the entry's - * associated variable. - * - * Results: - * None. - * - * Side effects: - * The string displayed in the entry will change. The selection, - * insertion point, and view may have to be adjusted to keep them - * within the bounds of the new string. Note: this procedure does - * *not* update the entry's associated variable, since that could - * result in an infinite loop. - * - *---------------------------------------------------------------------- - */ - -static void -EntrySetValue(entryPtr, value) - register Entry *entryPtr; /* Entry whose value is to be - * changed. */ - char *value; /* New text to display in entry. */ -{ - ckfree(entryPtr->string); - entryPtr->numChars = strlen(value); - entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1)); - strcpy(entryPtr->string, value); - if (entryPtr->selectFirst != -1) { - if (entryPtr->selectFirst >= entryPtr->numChars) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - } else if (entryPtr->selectLast > entryPtr->numChars) { - entryPtr->selectLast = entryPtr->numChars; - } - } - if (entryPtr->leftIndex >= entryPtr->numChars) { - entryPtr->leftIndex = entryPtr->numChars-1; - if (entryPtr->leftIndex < 0) { - entryPtr->leftIndex = 0; - } - } - if (entryPtr->insertPos > entryPtr->numChars) { - entryPtr->insertPos = entryPtr->numChars; - } - - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); -} - -/* - *-------------------------------------------------------------- - * - * EntryEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on entryes. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -EntryEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - Entry *entryPtr = (Entry *) clientData; - if (eventPtr->type == Expose) { - EventuallyRedraw(entryPtr); - entryPtr->flags |= BORDER_NEEDED; - } else if (eventPtr->type == DestroyNotify) { - if (entryPtr->tkwin != NULL) { - entryPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd); - } - if (entryPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr); - } - Tcl_EventuallyFree((ClientData) entryPtr, DestroyEntry); - } else if (eventPtr->type == ConfigureNotify) { - Tcl_Preserve((ClientData) entryPtr); - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); - Tcl_Release((ClientData) entryPtr); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - EntryFocusProc(entryPtr, 1); - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - EntryFocusProc(entryPtr, 0); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * EntryCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -EntryCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - Entry *entryPtr = (Entry *) clientData; - Tk_Window tkwin = entryPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - entryPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * GetEntryIndex -- - * - * Parse an index into an entry and return either its value - * or an error. - * - * Results: - * A standard Tcl result. If all went well, then *indexPtr is - * filled in with the index (into entryPtr) corresponding to - * string. The index value is guaranteed to lie between 0 and - * the number of characters in the string, inclusive. If an - * error occurs then an error message is left in interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -GetEntryIndex(interp, entryPtr, string, indexPtr) - Tcl_Interp *interp; /* For error messages. */ - Entry *entryPtr; /* Entry for which the index is being - * specified. */ - char *string; /* Specifies character in entryPtr. */ - int *indexPtr; /* Where to store converted index. */ -{ - size_t length; - - length = strlen(string); - - if (string[0] == 'a') { - if (strncmp(string, "anchor", length) == 0) { - *indexPtr = entryPtr->selectAnchor; - } else { - badIndex: - - /* - * Some of the paths here leave messages in interp->result, - * so we have to clear it out before storing our own message. - */ - - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - Tcl_AppendResult(interp, "bad entry index \"", string, - "\"", (char *) NULL); - return TCL_ERROR; - } - } else if (string[0] == 'e') { - if (strncmp(string, "end", length) == 0) { - *indexPtr = entryPtr->numChars; - } else { - goto badIndex; - } - } else if (string[0] == 'i') { - if (strncmp(string, "insert", length) == 0) { - *indexPtr = entryPtr->insertPos; - } else { - goto badIndex; - } - } else if (string[0] == 's') { - if (entryPtr->selectFirst == -1) { - interp->result = "selection isn't in entry"; - return TCL_ERROR; - } - if (length < 5) { - goto badIndex; - } - if (strncmp(string, "sel.first", length) == 0) { - *indexPtr = entryPtr->selectFirst; - } else if (strncmp(string, "sel.last", length) == 0) { - *indexPtr = entryPtr->selectLast; - } else { - goto badIndex; - } - } else if (string[0] == '@') { - int x, roundUp; - - if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) { - goto badIndex; - } - if (x < entryPtr->inset) { - x = entryPtr->inset; - } - roundUp = 0; - if (x >= (Tk_Width(entryPtr->tkwin) - entryPtr->inset)) { - x = Tk_Width(entryPtr->tkwin) - entryPtr->inset - 1; - roundUp = 1; - } - *indexPtr = Tk_PointToChar(entryPtr->textLayout, - x - entryPtr->layoutX, 0); - - /* - * Special trick: if the x-position was off-screen to the right, - * round the index up to refer to the character just after the - * last visible one on the screen. This is needed to enable the - * last character to be selected, for example. - */ - - if (roundUp && (*indexPtr < entryPtr->numChars)) { - *indexPtr += 1; - } - } else { - if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) { - goto badIndex; - } - if (*indexPtr < 0){ - *indexPtr = 0; - } else if (*indexPtr > entryPtr->numChars) { - *indexPtr = entryPtr->numChars; - } - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * EntryScanTo -- - * - * Given a y-coordinate (presumably of the curent mouse location) - * drag the view in the window to implement the scan operation. - * - * Results: - * None. - * - * Side effects: - * The view in the window may change. - * - *---------------------------------------------------------------------- - */ - -static void -EntryScanTo(entryPtr, x) - register Entry *entryPtr; /* Information about widget. */ - int x; /* X-coordinate to use for scan - * operation. */ -{ - int newLeftIndex; - - /* - * Compute new leftIndex for entry by amplifying the difference - * between the current position and the place where the scan - * started (the "mark" position). If we run off the left or right - * side of the entry, then reset the mark point so that the current - * position continues to correspond to the edge of the window. - * This means that the picture will start dragging as soon as the - * mouse reverses direction (without this reset, might have to slide - * mouse a long ways back before the picture starts moving again). - */ - - newLeftIndex = entryPtr->scanMarkIndex - - (10*(x - entryPtr->scanMarkX))/entryPtr->avgWidth; - if (newLeftIndex >= entryPtr->numChars) { - newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars-1; - entryPtr->scanMarkX = x; - } - if (newLeftIndex < 0) { - newLeftIndex = entryPtr->scanMarkIndex = 0; - entryPtr->scanMarkX = x; - } - if (newLeftIndex != entryPtr->leftIndex) { - entryPtr->leftIndex = newLeftIndex; - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * EntrySelectTo -- - * - * Modify the selection by moving its un-anchored end. This could - * make the selection either larger or smaller. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - *---------------------------------------------------------------------- - */ - -static void -EntrySelectTo(entryPtr, index) - register Entry *entryPtr; /* Information about widget. */ - int index; /* Index of element that is to - * become the "other" end of the - * selection. */ -{ - int newFirst, newLast; - - /* - * Grab the selection if we don't own it already. - */ - - if (!(entryPtr->flags & GOT_SELECTION) && (entryPtr->exportSelection)) { - Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection, - (ClientData) entryPtr); - entryPtr->flags |= GOT_SELECTION; - } - - /* - * Pick new starting and ending points for the selection. - */ - - if (entryPtr->selectAnchor > entryPtr->numChars) { - entryPtr->selectAnchor = entryPtr->numChars; - } - if (entryPtr->selectAnchor <= index) { - newFirst = entryPtr->selectAnchor; - newLast = index; - } else { - newFirst = index; - newLast = entryPtr->selectAnchor; - if (newLast < 0) { - newFirst = newLast = -1; - } - } - if ((entryPtr->selectFirst == newFirst) - && (entryPtr->selectLast == newLast)) { - return; - } - entryPtr->selectFirst = newFirst; - entryPtr->selectLast = newLast; - EventuallyRedraw(entryPtr); -} - -/* - *---------------------------------------------------------------------- - * - * EntryFetchSelection -- - * - * This procedure is called back by Tk when the selection is - * requested by someone. It returns part or all of the selection - * in a buffer provided by the caller. - * - * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -EntryFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about entry widget. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ -{ - Entry *entryPtr = (Entry *) clientData; - int count; - char *displayString; - - if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) { - return -1; - } - count = entryPtr->selectLast - entryPtr->selectFirst - offset; - if (count > maxBytes) { - count = maxBytes; - } - if (count <= 0) { - return 0; - } - if (entryPtr->displayString == NULL) { - displayString = entryPtr->string; - } else { - displayString = entryPtr->displayString; - } - strncpy(buffer, displayString + entryPtr->selectFirst + offset, - (size_t) count); - buffer[count] = '\0'; - return count; -} - -/* - *---------------------------------------------------------------------- - * - * EntryLostSelection -- - * - * This procedure is called back by Tk when the selection is - * grabbed away from an entry widget. - * - * Results: - * None. - * - * Side effects: - * The existing selection is unhighlighted, and the window is - * marked as not containing a selection. - * - *---------------------------------------------------------------------- - */ - -static void -EntryLostSelection(clientData) - ClientData clientData; /* Information about entry widget. */ -{ - Entry *entryPtr = (Entry *) clientData; - - entryPtr->flags &= ~GOT_SELECTION; - - /* - * On Windows and Mac systems, we want to remember the selection - * for the next time the focus enters the window. On Unix, we need - * to clear the selection since it is always visible. - */ - -#ifdef ALWAYS_SHOW_SELECTION - if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) { - entryPtr->selectFirst = -1; - entryPtr->selectLast = -1; - EventuallyRedraw(entryPtr); - } -#endif -} - -/* - *---------------------------------------------------------------------- - * - * EventuallyRedraw -- - * - * Ensure that an entry is eventually redrawn on the display. - * - * Results: - * None. - * - * Side effects: - * Information gets redisplayed. Right now we don't do selective - * redisplays: the whole window will be redrawn. This doesn't - * seem to hurt performance noticeably, but if it does then this - * could be changed. - * - *---------------------------------------------------------------------- - */ - -static void -EventuallyRedraw(entryPtr) - register Entry *entryPtr; /* Information about widget. */ -{ - if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) { - return; - } - - /* - * Right now we don't do selective redisplays: the whole window - * will be redrawn. This doesn't seem to hurt performance noticeably, - * but if it does then this could be changed. - */ - - if (!(entryPtr->flags & REDRAW_PENDING)) { - entryPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayEntry, (ClientData) entryPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * EntryVisibleRange -- - * - * Return information about the range of the entry that is - * currently visible. - * - * Results: - * *firstPtr and *lastPtr are modified to hold fractions between - * 0 and 1 identifying the range of characters visible in the - * entry. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -EntryVisibleRange(entryPtr, firstPtr, lastPtr) - Entry *entryPtr; /* Information about widget. */ - double *firstPtr; /* Return position of first visible - * character in widget. */ - double *lastPtr; /* Return position of char just after - * last visible one. */ -{ - int charsInWindow; - - if (entryPtr->numChars == 0) { - *firstPtr = 0.0; - *lastPtr = 1.0; - } else { - charsInWindow = Tk_PointToChar(entryPtr->textLayout, - Tk_Width(entryPtr->tkwin) - entryPtr->inset - - entryPtr->layoutX - 1, 0) + 1; - if (charsInWindow > entryPtr->numChars) { - /* - * If all chars were visible, then charsInWindow will be - * the index just after the last char that was visible. - */ - - charsInWindow = entryPtr->numChars; - } - charsInWindow -= entryPtr->leftIndex; - if (charsInWindow == 0) { - charsInWindow = 1; - } - *firstPtr = ((double) entryPtr->leftIndex)/entryPtr->numChars; - *lastPtr = ((double) (entryPtr->leftIndex + charsInWindow)) - /entryPtr->numChars; - } -} - -/* - *---------------------------------------------------------------------- - * - * EntryUpdateScrollbar -- - * - * This procedure is invoked whenever information has changed in - * an entry in a way that would invalidate a scrollbar display. - * If there is an associated scrollbar, then this procedure updates - * it by invoking a Tcl command. - * - * Results: - * None. - * - * Side effects: - * A Tcl command is invoked, and an additional command may be - * invoked to process errors in the command. - * - *---------------------------------------------------------------------- - */ - -static void -EntryUpdateScrollbar(entryPtr) - Entry *entryPtr; /* Information about widget. */ -{ - char args[100]; - int code; - double first, last; - Tcl_Interp *interp; - - if (entryPtr->scrollCmd == NULL) { - return; - } - - interp = entryPtr->interp; - Tcl_Preserve((ClientData) interp); - EntryVisibleRange(entryPtr, &first, &last); - sprintf(args, " %g %g", first, last); - code = Tcl_VarEval(interp, entryPtr->scrollCmd, args, (char *) NULL); - if (code != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (horizontal scrolling command executed by entry)"); - Tcl_BackgroundError(interp); - } - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - Tcl_Release((ClientData) interp); -} - -/* - *---------------------------------------------------------------------- - * - * EntryBlinkProc -- - * - * This procedure is called as a timer handler to blink the - * insertion cursor off and on. - * - * Results: - * None. - * - * Side effects: - * The cursor gets turned on or off, redisplay gets invoked, - * and this procedure reschedules itself. - * - *---------------------------------------------------------------------- - */ - -static void -EntryBlinkProc(clientData) - ClientData clientData; /* Pointer to record describing entry. */ -{ - register Entry *entryPtr = (Entry *) clientData; - - if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) { - return; - } - if (entryPtr->flags & CURSOR_ON) { - entryPtr->flags &= ~CURSOR_ON; - entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - entryPtr->insertOffTime, EntryBlinkProc, (ClientData) entryPtr); - } else { - entryPtr->flags |= CURSOR_ON; - entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr); - } - EventuallyRedraw(entryPtr); -} - -/* - *---------------------------------------------------------------------- - * - * EntryFocusProc -- - * - * This procedure is called whenever the entry gets or loses the - * input focus. It's also called whenever the window is reconfigured - * while it has the focus. - * - * Results: - * None. - * - * Side effects: - * The cursor gets turned on or off. - * - *---------------------------------------------------------------------- - */ - -static void -EntryFocusProc(entryPtr, gotFocus) - register Entry *entryPtr; /* Entry that got or lost focus. */ - int gotFocus; /* 1 means window is getting focus, 0 means - * it's losing it. */ -{ - Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler); - if (gotFocus) { - entryPtr->flags |= GOT_FOCUS | CURSOR_ON; - if (entryPtr->insertOffTime != 0) { - entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - entryPtr->insertOnTime, EntryBlinkProc, - (ClientData) entryPtr); - } - } else { - entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON); - entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - } - EventuallyRedraw(entryPtr); -} - -/* - *-------------------------------------------------------------- - * - * EntryTextVarProc -- - * - * This procedure is invoked when someone changes the variable - * whose contents are to be displayed in an entry. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The text displayed in the entry will change to match the - * variable. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -EntryTextVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about button. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Not used. */ - char *name2; /* Not used. */ - int flags; /* Information about what happened. */ -{ - register Entry *entryPtr = (Entry *) clientData; - char *value; - - /* - * If the variable is unset, then immediately recreate it unless - * the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string, - TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, entryPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - EntryTextVarProc, clientData); - } - return (char *) NULL; - } - - /* - * Update the entry's text with the value of the variable, unless - * the entry already has that value (this happens when the variable - * changes value because we changed it because someone typed in - * the entry). - */ - - value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (strcmp(value, entryPtr->string) != 0) { - EntrySetValue(entryPtr, value); - } - return (char *) NULL; -} diff --git a/generic/tkError.c b/generic/tkError.c deleted file mode 100644 index a601720..0000000 --- a/generic/tkError.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * tkError.c -- - * - * This file provides a high-performance mechanism for - * selectively dealing with errors that occur in talking - * to the X server. This is useful, for example, when - * communicating with a window that may not exist. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkError.c,v 1.2 1998/09/14 18:23:09 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * The default X error handler gets saved here, so that it can - * be invoked if an error occurs that we can't handle. - */ - -static int (*defaultHandler) _ANSI_ARGS_((Display *display, - XErrorEvent *eventPtr)) = NULL; - - -/* - * Forward references to procedures declared later in this file: - */ - -static int ErrorProc _ANSI_ARGS_((Display *display, - XErrorEvent *errEventPtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_CreateErrorHandler -- - * - * Arrange for all a given procedure to be invoked whenever - * certain errors occur. - * - * Results: - * The return value is a token identifying the handler; - * it must be passed to Tk_DeleteErrorHandler to delete the - * handler. - * - * Side effects: - * If an X error occurs that matches the error, request, - * and minor arguments, then errorProc will be invoked. - * ErrorProc should have the following structure: - * - * int - * errorProc(clientData, errorEventPtr) - * caddr_t clientData; - * XErrorEvent *errorEventPtr; - * { - * } - * - * The clientData argument will be the same as the clientData - * argument to this procedure, and errorEvent will describe - * the error. If errorProc returns 0, it means that it - * completely "handled" the error: no further processing - * should be done. If errorProc returns 1, it means that it - * didn't know how to deal with the error, so we should look - * for other error handlers, or invoke the default error - * handler if no other handler returns zero. Handlers are - * invoked in order of age: youngest handler first. - * - * Note: errorProc will only be called for errors associated - * with X requests made AFTER this call, but BEFORE the handler - * is deleted by calling Tk_DeleteErrorHandler. - * - *-------------------------------------------------------------- - */ - -Tk_ErrorHandler -Tk_CreateErrorHandler(display, error, request, minorCode, errorProc, clientData) - Display *display; /* Display for which to handle - * errors. */ - int error; /* Consider only errors with this - * error_code (-1 means consider - * all errors). */ - int request; /* Consider only errors with this - * major request code (-1 means - * consider all major codes). */ - int minorCode; /* Consider only errors with this - * minor request code (-1 means - * consider all minor codes). */ - Tk_ErrorProc *errorProc; /* Procedure to invoke when a - * matching error occurs. NULL means - * just ignore matching errors. */ - ClientData clientData; /* Arbitrary value to pass to - * errorProc. */ -{ - register TkErrorHandler *errorPtr; - register TkDisplay *dispPtr; - - /* - * Find the display. If Tk doesn't know about this display then - * it's an error: panic. - */ - - dispPtr = TkGetDisplay(display); - if (dispPtr == NULL) { - panic("Unknown display passed to Tk_CreateErrorHandler"); - } - - /* - * Make sure that X calls us whenever errors occur. - */ - - if (defaultHandler == NULL) { - defaultHandler = XSetErrorHandler(ErrorProc); - } - - /* - * Create the handler record. - */ - - errorPtr = (TkErrorHandler *) ckalloc(sizeof(TkErrorHandler)); - errorPtr->dispPtr = dispPtr; - errorPtr->firstRequest = NextRequest(display); - errorPtr->lastRequest = (unsigned) -1; - errorPtr->error = error; - errorPtr->request = request; - errorPtr->minorCode = minorCode; - errorPtr->errorProc = errorProc; - errorPtr->clientData = clientData; - errorPtr->nextPtr = dispPtr->errorPtr; - dispPtr->errorPtr = errorPtr; - - return (Tk_ErrorHandler) errorPtr; -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteErrorHandler -- - * - * Do not use an error handler anymore. - * - * Results: - * None. - * - * Side effects: - * The handler denoted by the "handler" argument will not - * be invoked for any X errors associated with requests - * made after this call. However, if errors arrive later - * for requests made BEFORE this call, then the handler - * will still be invoked. Call XSync if you want to be - * sure that all outstanding errors have been received - * and processed. - * - *-------------------------------------------------------------- - */ - -void -Tk_DeleteErrorHandler(handler) - Tk_ErrorHandler handler; /* Token for handler to delete; - * was previous return value from - * Tk_CreateErrorHandler. */ -{ - register TkErrorHandler *errorPtr = (TkErrorHandler *) handler; - register TkDisplay *dispPtr = errorPtr->dispPtr; - - errorPtr->lastRequest = NextRequest(dispPtr->display) - 1; - - /* - * Every once-in-a-while, cleanup handlers that are no longer - * active. We probably won't be able to free the handler that - * was just deleted (need to wait for any outstanding requests to - * be processed by server), but there may be previously-deleted - * handlers that are now ready for garbage collection. To reduce - * the cost of the cleanup, let a few dead handlers pile up, then - * clean them all at once. This adds a bit of overhead to errors - * that might occur while the dead handlers are hanging around, - * but reduces the overhead of scanning the list to clean up - * (particularly if there are many handlers that stay around - * forever). - */ - - dispPtr->deleteCount += 1; - if (dispPtr->deleteCount >= 10) { - register TkErrorHandler *prevPtr; - TkErrorHandler *nextPtr; - int lastSerial; - - dispPtr->deleteCount = 0; - lastSerial = LastKnownRequestProcessed(dispPtr->display); - errorPtr = dispPtr->errorPtr; - for (prevPtr = NULL; errorPtr != NULL; errorPtr = nextPtr) { - nextPtr = errorPtr->nextPtr; - if ((errorPtr->lastRequest != (unsigned long) -1) - && (errorPtr->lastRequest <= (unsigned long) lastSerial)) { - if (prevPtr == NULL) { - dispPtr->errorPtr = nextPtr; - } else { - prevPtr->nextPtr = nextPtr; - } - ckfree((char *) errorPtr); - continue; - } - prevPtr = errorPtr; - } - } -} - -/* - *-------------------------------------------------------------- - * - * ErrorProc -- - * - * This procedure is invoked by the X system when error - * events arrive. - * - * Results: - * If it returns, the return value is zero. However, - * it is possible that one of the error handlers may - * just exit. - * - * Side effects: - * This procedure does two things. First, it uses the - * serial # in the error event to eliminate handlers whose - * expiration serials are now in the past. Second, it - * invokes any handlers that want to deal with the error. - * - *-------------------------------------------------------------- - */ - -static int -ErrorProc(display, errEventPtr) - Display *display; /* Display for which error - * occurred. */ - register XErrorEvent *errEventPtr; /* Information about error. */ -{ - register TkDisplay *dispPtr; - register TkErrorHandler *errorPtr; - - /* - * See if we know anything about the display. If not, then - * invoke the default error handler. - */ - - dispPtr = TkGetDisplay(display); - if (dispPtr == NULL) { - goto couldntHandle; - } - - /* - * Otherwise invoke any relevant handlers for the error, in order. - */ - - for (errorPtr = dispPtr->errorPtr; errorPtr != NULL; - errorPtr = errorPtr->nextPtr) { - if ((errorPtr->firstRequest > errEventPtr->serial) - || ((errorPtr->error != -1) - && (errorPtr->error != errEventPtr->error_code)) - || ((errorPtr->request != -1) - && (errorPtr->request != errEventPtr->request_code)) - || ((errorPtr->minorCode != -1) - && (errorPtr->minorCode != errEventPtr->minor_code)) - || ((errorPtr->lastRequest != (unsigned long) -1) - && (errorPtr->lastRequest < errEventPtr->serial))) { - continue; - } - if (errorPtr->errorProc == NULL) { - return 0; - } else { - if ((*errorPtr->errorProc)(errorPtr->clientData, - errEventPtr) == 0) { - return 0; - } - } - } - - /* - * See if the error is a BadWindow error. If so, and it refers - * to a window that still exists in our window table, then ignore - * the error. Errors like this can occur if a window owned by us - * is deleted by someone externally, like a window manager. We'll - * ignore the errors at least long enough to clean up internally and - * remove the entry from the window table. - * - * NOTE: For embedding, we must also check whether the window was - * recently deleted. If so, it may be that Tk generated operations on - * windows that were deleted by the container. Now we are getting - * the errors (BadWindow) after Tk already deleted the window itself. - */ - - if ((errEventPtr->error_code == BadWindow) && - ((Tk_IdToWindow(display, (Window) errEventPtr->resourceid) != - NULL) || - (TkpWindowWasRecentlyDeleted((Window) errEventPtr->resourceid, - dispPtr)))) { - return 0; - } - - /* - * We couldn't handle the error. Use the default handler. - */ - - couldntHandle: - return (*defaultHandler)(display, errEventPtr); -} diff --git a/generic/tkEvent.c b/generic/tkEvent.c deleted file mode 100644 index 2e32b8f..0000000 --- a/generic/tkEvent.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * tkEvent.c -- - * - * This file provides basic low-level facilities for managing - * X events in Tk. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkEvent.c,v 1.2 1998/09/14 18:23:09 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" -#include <signal.h> - -/* - * There's a potential problem if a handler is deleted while it's - * current (i.e. its procedure is executing), since Tk_HandleEvent - * will need to read the handler's "nextPtr" field when the procedure - * returns. To handle this problem, structures of the type below - * indicate the next handler to be processed for any (recursively - * nested) dispatches in progress. The nextHandler fields get - * updated if the handlers pointed to are deleted. Tk_HandleEvent - * also needs to know if the entire window gets deleted; the winPtr - * field is set to zero if that particular window gets deleted. - */ - -typedef struct InProgress { - XEvent *eventPtr; /* Event currently being handled. */ - TkWindow *winPtr; /* Window for event. Gets set to None if - * window is deleted while event is being - * handled. */ - TkEventHandler *nextHandler; /* Next handler in search. */ - struct InProgress *nextPtr; /* Next higher nested search. */ -} InProgress; - -static InProgress *pendingPtr = NULL; - /* Topmost search in progress, or - * NULL if none. */ - -/* - * For each call to Tk_CreateGenericHandler, an instance of the following - * structure will be created. All of the active handlers are linked into a - * list. - */ - -typedef struct GenericHandler { - Tk_GenericProc *proc; /* Procedure to dispatch on all X events. */ - ClientData clientData; /* Client data to pass to procedure. */ - int deleteFlag; /* Flag to set when this handler is deleted. */ - struct GenericHandler *nextPtr; - /* Next handler in list of all generic - * handlers, or NULL for end of list. */ -} GenericHandler; - -static GenericHandler *genericList = NULL; - /* First handler in the list, or NULL. */ -static GenericHandler *lastGenericPtr = NULL; - /* Last handler in list. */ - -/* - * There's a potential problem if Tk_HandleEvent is entered recursively. - * A handler cannot be deleted physically until we have returned from - * calling it. Otherwise, we're looking at unallocated memory in advancing to - * its `next' entry. We deal with the problem by using the `delete flag' and - * deleting handlers only when it's known that there's no handler active. - * - * The following variable has a non-zero value when a handler is active. - */ - -static int genericHandlersActive = 0; - -/* - * The following structure is used for queueing X-style events on the - * Tcl event queue. - */ - -typedef struct TkWindowEvent { - Tcl_Event header; /* Standard information for all events. */ - XEvent event; /* The X event. */ -} TkWindowEvent; - -/* - * Array of event masks corresponding to each X event: - */ - -static unsigned long eventMasks[TK_LASTEVENT] = { - 0, - 0, - KeyPressMask, /* KeyPress */ - KeyReleaseMask, /* KeyRelease */ - ButtonPressMask, /* ButtonPress */ - ButtonReleaseMask, /* ButtonRelease */ - PointerMotionMask|PointerMotionHintMask|ButtonMotionMask - |Button1MotionMask|Button2MotionMask|Button3MotionMask - |Button4MotionMask|Button5MotionMask, - /* MotionNotify */ - EnterWindowMask, /* EnterNotify */ - LeaveWindowMask, /* LeaveNotify */ - FocusChangeMask, /* FocusIn */ - FocusChangeMask, /* FocusOut */ - KeymapStateMask, /* KeymapNotify */ - ExposureMask, /* Expose */ - ExposureMask, /* GraphicsExpose */ - ExposureMask, /* NoExpose */ - VisibilityChangeMask, /* VisibilityNotify */ - SubstructureNotifyMask, /* CreateNotify */ - StructureNotifyMask, /* DestroyNotify */ - StructureNotifyMask, /* UnmapNotify */ - StructureNotifyMask, /* MapNotify */ - SubstructureRedirectMask, /* MapRequest */ - StructureNotifyMask, /* ReparentNotify */ - StructureNotifyMask, /* ConfigureNotify */ - SubstructureRedirectMask, /* ConfigureRequest */ - StructureNotifyMask, /* GravityNotify */ - ResizeRedirectMask, /* ResizeRequest */ - StructureNotifyMask, /* CirculateNotify */ - SubstructureRedirectMask, /* CirculateRequest */ - PropertyChangeMask, /* PropertyNotify */ - 0, /* SelectionClear */ - 0, /* SelectionRequest */ - 0, /* SelectionNotify */ - ColormapChangeMask, /* ColormapNotify */ - 0, /* ClientMessage */ - 0, /* Mapping Notify */ - VirtualEventMask, /* VirtualEvents */ - ActivateMask, /* ActivateNotify */ - ActivateMask /* DeactivateNotify */ -}; - -/* - * If someone has called Tk_RestrictEvents, the information below - * keeps track of it. - */ - -static Tk_RestrictProc *restrictProc; - /* Procedure to call. NULL means no - * restrictProc is currently in effect. */ -static ClientData restrictArg; /* Argument to pass to restrictProc. */ - -/* - * Prototypes for procedures that are only referenced locally within - * this file. - */ - -static void DelayedMotionProc _ANSI_ARGS_((ClientData clientData)); -static int WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr, - int flags)); - -/* - *-------------------------------------------------------------- - * - * Tk_CreateEventHandler -- - * - * Arrange for a given procedure to be invoked whenever - * events from a given class occur in a given window. - * - * Results: - * None. - * - * Side effects: - * From now on, whenever an event of the type given by - * mask occurs for token and is processed by Tk_HandleEvent, - * proc will be called. See the manual entry for details - * of the calling sequence and return value for proc. - * - *-------------------------------------------------------------- - */ - -void -Tk_CreateEventHandler(token, mask, proc, clientData) - Tk_Window token; /* Token for window in which to - * create handler. */ - unsigned long mask; /* Events for which proc should - * be called. */ - Tk_EventProc *proc; /* Procedure to call for each - * selected event */ - ClientData clientData; /* Arbitrary data to pass to proc. */ -{ - register TkEventHandler *handlerPtr; - register TkWindow *winPtr = (TkWindow *) token; - int found; - - /* - * Skim through the list of existing handlers to (a) compute the - * overall event mask for the window (so we can pass this new - * value to the X system) and (b) see if there's already a handler - * declared with the same callback and clientData (if so, just - * change the mask). If no existing handler matches, then create - * a new handler. - */ - - found = 0; - if (winPtr->handlerList == NULL) { - handlerPtr = (TkEventHandler *) ckalloc( - (unsigned) sizeof(TkEventHandler)); - winPtr->handlerList = handlerPtr; - goto initHandler; - } else { - for (handlerPtr = winPtr->handlerList; ; - handlerPtr = handlerPtr->nextPtr) { - if ((handlerPtr->proc == proc) - && (handlerPtr->clientData == clientData)) { - handlerPtr->mask = mask; - found = 1; - } - if (handlerPtr->nextPtr == NULL) { - break; - } - } - } - - /* - * Create a new handler if no matching old handler was found. - */ - - if (!found) { - handlerPtr->nextPtr = (TkEventHandler *) - ckalloc(sizeof(TkEventHandler)); - handlerPtr = handlerPtr->nextPtr; - initHandler: - handlerPtr->mask = mask; - handlerPtr->proc = proc; - handlerPtr->clientData = clientData; - handlerPtr->nextPtr = NULL; - } - - /* - * No need to call XSelectInput: Tk always selects on all events - * for all windows (needed to support bindings on classes and "all"). - */ -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteEventHandler -- - * - * Delete a previously-created handler. - * - * Results: - * None. - * - * Side effects: - * If there existed a handler as described by the - * parameters, the handler is deleted so that proc - * will not be invoked again. - * - *-------------------------------------------------------------- - */ - -void -Tk_DeleteEventHandler(token, mask, proc, clientData) - Tk_Window token; /* Same as corresponding arguments passed */ - unsigned long mask; /* previously to Tk_CreateEventHandler. */ - Tk_EventProc *proc; - ClientData clientData; -{ - register TkEventHandler *handlerPtr; - register InProgress *ipPtr; - TkEventHandler *prevPtr; - register TkWindow *winPtr = (TkWindow *) token; - - /* - * Find the event handler to be deleted, or return - * immediately if it doesn't exist. - */ - - for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ; - prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) { - if (handlerPtr == NULL) { - return; - } - if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc) - && (handlerPtr->clientData == clientData)) { - break; - } - } - - /* - * If Tk_HandleEvent is about to process this handler, tell it to - * process the next one instead. - */ - - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { - if (ipPtr->nextHandler == handlerPtr) { - ipPtr->nextHandler = handlerPtr->nextPtr; - } - } - - /* - * Free resources associated with the handler. - */ - - if (prevPtr == NULL) { - winPtr->handlerList = handlerPtr->nextPtr; - } else { - prevPtr->nextPtr = handlerPtr->nextPtr; - } - ckfree((char *) handlerPtr); - - - /* - * No need to call XSelectInput: Tk always selects on all events - * for all windows (needed to support bindings on classes and "all"). - */ -} - -/*-------------------------------------------------------------- - * - * Tk_CreateGenericHandler -- - * - * Register a procedure to be called on each X event, regardless - * of display or window. Generic handlers are useful for capturing - * events that aren't associated with windows, or events for windows - * not managed by Tk. - * - * Results: - * None. - * - * Side Effects: - * From now on, whenever an X event is given to Tk_HandleEvent, - * invoke proc, giving it clientData and the event as arguments. - * - *-------------------------------------------------------------- - */ - -void -Tk_CreateGenericHandler(proc, clientData) - Tk_GenericProc *proc; /* Procedure to call on every event. */ - ClientData clientData; /* One-word value to pass to proc. */ -{ - GenericHandler *handlerPtr; - - handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler)); - - handlerPtr->proc = proc; - handlerPtr->clientData = clientData; - handlerPtr->deleteFlag = 0; - handlerPtr->nextPtr = NULL; - if (genericList == NULL) { - genericList = handlerPtr; - } else { - lastGenericPtr->nextPtr = handlerPtr; - } - lastGenericPtr = handlerPtr; -} - -/* - *-------------------------------------------------------------- - * - * Tk_DeleteGenericHandler -- - * - * Delete a previously-created generic handler. - * - * Results: - * None. - * - * Side Effects: - * If there existed a handler as described by the parameters, - * that handler is logically deleted so that proc will not be - * invoked again. The physical deletion happens in the event - * loop in Tk_HandleEvent. - * - *-------------------------------------------------------------- - */ - -void -Tk_DeleteGenericHandler(proc, clientData) - Tk_GenericProc *proc; - ClientData clientData; -{ - GenericHandler * handler; - - for (handler = genericList; handler; handler = handler->nextPtr) { - if ((handler->proc == proc) && (handler->clientData == clientData)) { - handler->deleteFlag = 1; - } - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_HandleEvent -- - * - * Given an event, invoke all the handlers that have - * been registered for the event. - * - * Results: - * None. - * - * Side effects: - * Depends on the handlers. - * - *-------------------------------------------------------------- - */ - -void -Tk_HandleEvent(eventPtr) - XEvent *eventPtr; /* Event to dispatch. */ -{ - register TkEventHandler *handlerPtr; - register GenericHandler *genericPtr; - register GenericHandler *genPrevPtr; - TkWindow *winPtr; - unsigned long mask; - InProgress ip; - Window handlerWindow; - TkDisplay *dispPtr; - Tcl_Interp *interp = (Tcl_Interp *) NULL; - - /* - * Next, invoke all the generic event handlers (those that are - * invoked for all events). If a generic event handler reports that - * an event is fully processed, go no further. - */ - - for (genPrevPtr = NULL, genericPtr = genericList; genericPtr != NULL; ) { - if (genericPtr->deleteFlag) { - if (!genericHandlersActive) { - GenericHandler *tmpPtr; - - /* - * This handler needs to be deleted and there are no - * calls pending through the handler, so now is a safe - * time to delete it. - */ - - tmpPtr = genericPtr->nextPtr; - if (genPrevPtr == NULL) { - genericList = tmpPtr; - } else { - genPrevPtr->nextPtr = tmpPtr; - } - if (tmpPtr == NULL) { - lastGenericPtr = genPrevPtr; - } - (void) ckfree((char *) genericPtr); - genericPtr = tmpPtr; - continue; - } - } else { - int done; - - genericHandlersActive++; - done = (*genericPtr->proc)(genericPtr->clientData, eventPtr); - genericHandlersActive--; - if (done) { - return; - } - } - genPrevPtr = genericPtr; - genericPtr = genPrevPtr->nextPtr; - } - - /* - * If the event is a MappingNotify event, find its display and - * refresh the keyboard mapping information for the display. - * After that there's nothing else to do with the event, so just - * quit. - */ - - if (eventPtr->type == MappingNotify) { - dispPtr = TkGetDisplay(eventPtr->xmapping.display); - if (dispPtr != NULL) { - XRefreshKeyboardMapping(&eventPtr->xmapping); - dispPtr->bindInfoStale = 1; - } - return; - } - - /* - * Events selected by StructureNotify require special handling. - * They look the same as those selected by SubstructureNotify. - * The only difference is whether the "event" and "window" fields - * are the same. Compare the two fields and convert StructureNotify - * to SubstructureNotify if necessary. - */ - - handlerWindow = eventPtr->xany.window; - mask = eventMasks[eventPtr->xany.type]; - if (mask == StructureNotifyMask) { - if (eventPtr->xmap.event != eventPtr->xmap.window) { - mask = SubstructureNotifyMask; - handlerWindow = eventPtr->xmap.event; - } - } - winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow); - if (winPtr == NULL) { - - /* - * There isn't a TkWindow structure for this window. - * However, if the event is a PropertyNotify event then call - * the selection manager (it deals beneath-the-table with - * certain properties). - */ - - if (eventPtr->type == PropertyNotify) { - TkSelPropProc(eventPtr); - } - return; - } - - /* - * Once a window has started getting deleted, don't process any more - * events for it except for the DestroyNotify event. This check is - * needed because a DestroyNotify handler could re-invoke the event - * loop, causing other pending events to be handled for the window - * (the window doesn't get totally expunged from our tables until - * after the DestroyNotify event has been completely handled). - */ - - if ((winPtr->flags & TK_ALREADY_DEAD) - && (eventPtr->type != DestroyNotify)) { - return; - } - - if (winPtr->mainPtr != NULL) { - - /* - * Protect interpreter for this window from possible deletion - * while we are dealing with the event for this window. Thus, - * widget writers do not have to worry about protecting the - * interpreter in their own code. - */ - - interp = winPtr->mainPtr->interp; - Tcl_Preserve((ClientData) interp); - - /* - * Call focus-related code to look at FocusIn, FocusOut, Enter, - * and Leave events; depending on its return value, ignore the - * event. - */ - - if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask)) - && !TkFocusFilterEvent(winPtr, eventPtr)) { - Tcl_Release((ClientData) interp); - return; - } - - /* - * Redirect KeyPress and KeyRelease events to the focus window, - * or ignore them entirely if there is no focus window. - */ - - if (mask & (KeyPressMask|KeyReleaseMask)) { - winPtr->dispPtr->lastEventTime = eventPtr->xkey.time; - winPtr = TkFocusKeyEvent(winPtr, eventPtr); - if (winPtr == NULL) { - Tcl_Release((ClientData) interp); - return; - } - } - - /* - * Call a grab-related procedure to do special processing on - * pointer events. - */ - - if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask - |EnterWindowMask|LeaveWindowMask)) { - if (mask & (ButtonPressMask|ButtonReleaseMask)) { - winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time; - } else if (mask & PointerMotionMask) { - winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time; - } else { - winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time; - } - if (TkPointerEvent(eventPtr, winPtr) == 0) { - goto done; - } - } - } - -#ifdef TK_USE_INPUT_METHODS - /* - * Pass the event to the input method(s), if there are any, and - * discard the event if the input method(s) insist. Create the - * input context for the window if it hasn't already been done - * (XFilterEvent needs this context). - */ - - if (!(winPtr->flags & TK_CHECKED_IC)) { - if (winPtr->dispPtr->inputMethod != NULL) { - winPtr->inputContext = XCreateIC( - winPtr->dispPtr->inputMethod, XNInputStyle, - XIMPreeditNothing|XIMStatusNothing, - XNClientWindow, winPtr->window, - XNFocusWindow, winPtr->window, NULL); - } - winPtr->flags |= TK_CHECKED_IC; - } - if (XFilterEvent(eventPtr, None)) { - goto done; - } -#endif /* TK_USE_INPUT_METHODS */ - - /* - * For events where it hasn't already been done, update the current - * time in the display. - */ - - if (eventPtr->type == PropertyNotify) { - winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time; - } - - /* - * There's a potential interaction here with Tk_DeleteEventHandler. - * Read the documentation for pendingPtr. - */ - - ip.eventPtr = eventPtr; - ip.winPtr = winPtr; - ip.nextHandler = NULL; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; - if (mask == 0) { - if ((eventPtr->type == SelectionClear) - || (eventPtr->type == SelectionRequest) - || (eventPtr->type == SelectionNotify)) { - TkSelEventProc((Tk_Window) winPtr, eventPtr); - } else if ((eventPtr->type == ClientMessage) - && (eventPtr->xclient.message_type == - Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) { - TkWmProtocolEventProc(winPtr, eventPtr); - } - } else { - for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) { - if ((handlerPtr->mask & mask) != 0) { - ip.nextHandler = handlerPtr->nextPtr; - (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr); - handlerPtr = ip.nextHandler; - } else { - handlerPtr = handlerPtr->nextPtr; - } - } - - /* - * Pass the event to the "bind" command mechanism. But, don't - * do this for SubstructureNotify events. The "bind" command - * doesn't support them anyway, and it's easier to filter out - * these events here than in the lower-level procedures. - */ - - if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) { - TkBindEventProc(winPtr, eventPtr); - } - } - pendingPtr = ip.nextPtr; -done: - - /* - * Release the interpreter for this window so that it can be potentially - * deleted if requested. - */ - - if (interp != (Tcl_Interp *) NULL) { - Tcl_Release((ClientData) interp); - } -} - -/* - *-------------------------------------------------------------- - * - * TkEventDeadWindow -- - * - * This procedure is invoked when it is determined that - * a window is dead. It cleans up event-related information - * about the window. - * - * Results: - * None. - * - * Side effects: - * Various things get cleaned up and recycled. - * - *-------------------------------------------------------------- - */ - -void -TkEventDeadWindow(winPtr) - TkWindow *winPtr; /* Information about the window - * that is being deleted. */ -{ - register TkEventHandler *handlerPtr; - register InProgress *ipPtr; - - /* - * While deleting all the handlers, be careful to check for - * Tk_HandleEvent being about to process one of the deleted - * handlers. If it is, tell it to quit (all of the handlers - * are being deleted). - */ - - while (winPtr->handlerList != NULL) { - handlerPtr = winPtr->handlerList; - winPtr->handlerList = handlerPtr->nextPtr; - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { - if (ipPtr->nextHandler == handlerPtr) { - ipPtr->nextHandler = NULL; - } - if (ipPtr->winPtr == winPtr) { - ipPtr->winPtr = None; - } - } - ckfree((char *) handlerPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkCurrentTime -- - * - * Try to deduce the current time. "Current time" means the time - * of the event that led to the current code being executed, which - * means the time in the most recently-nested invocation of - * Tk_HandleEvent. - * - * Results: - * The return value is the time from the current event, or - * CurrentTime if there is no current event or if the current - * event contains no time. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Time -TkCurrentTime(dispPtr) - TkDisplay *dispPtr; /* Display for which the time is desired. */ -{ - register XEvent *eventPtr; - - if (pendingPtr == NULL) { - return dispPtr->lastEventTime; - } - eventPtr = pendingPtr->eventPtr; - switch (eventPtr->type) { - case ButtonPress: - case ButtonRelease: - return eventPtr->xbutton.time; - case KeyPress: - case KeyRelease: - return eventPtr->xkey.time; - case MotionNotify: - return eventPtr->xmotion.time; - case EnterNotify: - case LeaveNotify: - return eventPtr->xcrossing.time; - case PropertyNotify: - return eventPtr->xproperty.time; - } - return dispPtr->lastEventTime; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_RestrictEvents -- - * - * This procedure is used to globally restrict the set of events - * that will be dispatched. The restriction is done by filtering - * all incoming X events through a procedure that determines - * whether they are to be processed immediately, deferred, or - * discarded. - * - * Results: - * The return value is the previous restriction procedure in effect, - * if there was one, or NULL if there wasn't. - * - * Side effects: - * From now on, proc will be called to determine whether to process, - * defer or discard each incoming X event. - * - *---------------------------------------------------------------------- - */ - -Tk_RestrictProc * -Tk_RestrictEvents(proc, arg, prevArgPtr) - Tk_RestrictProc *proc; /* Procedure to call for each incoming - * event. */ - ClientData arg; /* Arbitrary argument to pass to proc. */ - ClientData *prevArgPtr; /* Place to store information about previous - * argument. */ -{ - Tk_RestrictProc *prev; - - prev = restrictProc; - *prevArgPtr = restrictArg; - restrictProc = proc; - restrictArg = arg; - return prev; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_QueueWindowEvent -- - * - * Given an X-style window event, this procedure adds it to the - * Tcl event queue at the given position. This procedure also - * performs mouse motion event collapsing if possible. - * - * Results: - * None. - * - * Side effects: - * Adds stuff to the event queue, which will eventually be - * processed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_QueueWindowEvent(eventPtr, position) - XEvent *eventPtr; /* Event to add to queue. This - * procedures copies it before adding - * it to the queue. */ - Tcl_QueuePosition position; /* Where to put it on the queue: - * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, - * or TCL_QUEUE_MARK. */ -{ - TkWindowEvent *wevPtr; - TkDisplay *dispPtr; - - /* - * Find our display structure for the event's display. - */ - - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { - if (dispPtr == NULL) { - return; - } - if (dispPtr->display == eventPtr->xany.display) { - break; - } - } - - if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) { - if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window - == dispPtr->delayedMotionPtr->event.xmotion.window)) { - /* - * The new event is a motion event in the same window as the - * saved motion event. Just replace the saved event with the - * new one. - */ - - dispPtr->delayedMotionPtr->event = *eventPtr; - return; - } else if ((eventPtr->type != GraphicsExpose) - && (eventPtr->type != NoExpose) - && (eventPtr->type != Expose)) { - /* - * The new event may conflict with the saved motion event. Queue - * the saved motion event now so that it will be processed before - * the new event. - */ - - Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position); - dispPtr->delayedMotionPtr = NULL; - Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr); - } - } - - wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent)); - wevPtr->header.proc = WindowEventProc; - wevPtr->event = *eventPtr; - if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) { - /* - * The new event is a motion event so don't queue it immediately; - * save it around in case another motion event arrives that it can - * be collapsed with. - */ - - if (dispPtr->delayedMotionPtr != NULL) { - panic("Tk_QueueWindowEvent found unexpected delayed motion event"); - } - dispPtr->delayedMotionPtr = wevPtr; - Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr); - } else { - Tcl_QueueEvent(&wevPtr->header, position); - } -} - -/* - *--------------------------------------------------------------------------- - * - * TkQueueEventForAllChildren -- - * - * Given an XEvent, recursively queue the event for this window and - * all non-toplevel children of the given window. - * - * Results: - * None. - * - * Side effects: - * Events queued. - * - *--------------------------------------------------------------------------- - */ - -void -TkQueueEventForAllChildren(winPtr, eventPtr) - TkWindow *winPtr; /* Window to which event is sent. */ - XEvent *eventPtr; /* The event to be sent. */ -{ - TkWindow *childPtr; - - eventPtr->xany.window = winPtr->window; - Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); - - childPtr = winPtr->childList; - while (childPtr != NULL) { - if (!Tk_IsTopLevel(childPtr)) { - TkQueueEventForAllChildren(childPtr, eventPtr); - } - childPtr = childPtr->nextPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * WindowEventProc -- - * - * This procedure is called by Tcl_DoOneEvent when a window event - * reaches the front of the event queue. This procedure is responsible - * for actually handling the event. - * - * Results: - * Returns 1 if the event was handled, meaning it should be removed - * from the queue. Returns 0 if the event was not handled, meaning - * it should stay on the queue. The event isn't handled if the - * TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc - * prevents the event from being handled. - * - * Side effects: - * Whatever the event handlers for the event do. - * - *---------------------------------------------------------------------- - */ - -static int -WindowEventProc(evPtr, flags) - Tcl_Event *evPtr; /* Event to service. */ - int flags; /* Flags that indicate what events to - * handle, such as TCL_WINDOW_EVENTS. */ -{ - TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr; - Tk_RestrictAction result; - - if (!(flags & TCL_WINDOW_EVENTS)) { - return 0; - } - if (restrictProc != NULL) { - result = (*restrictProc)(restrictArg, &wevPtr->event); - if (result != TK_PROCESS_EVENT) { - if (result == TK_DEFER_EVENT) { - return 0; - } else { - /* - * TK_DELETE_EVENT: return and say we processed the event, - * even though we didn't do anything at all. - */ - return 1; - } - } - } - Tk_HandleEvent(&wevPtr->event); - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * DelayedMotionProc -- - * - * This procedure is invoked as an idle handler when a mouse motion - * event has been delayed. It queues the delayed event so that it - * will finally be serviced. - * - * Results: - * None. - * - * Side effects: - * The delayed mouse motion event gets added to the Tcl event - * queue for servicing. - * - *---------------------------------------------------------------------- - */ - -static void -DelayedMotionProc(clientData) - ClientData clientData; /* Pointer to display containing a delayed - * motion event to be serviced. */ -{ - TkDisplay *dispPtr = (TkDisplay *) clientData; - - if (dispPtr->delayedMotionPtr == NULL) { - panic("DelayedMotionProc found no delayed mouse motion event"); - } - Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL); - dispPtr->delayedMotionPtr = NULL; -} - -/* - *-------------------------------------------------------------- - * - * Tk_MainLoop -- - * - * Call Tcl_DoOneEvent over and over again in an infinite - * loop as long as there exist any main windows. - * - * Results: - * None. - * - * Side effects: - * Arbitrary; depends on handlers for events. - * - *-------------------------------------------------------------- - */ - -void -Tk_MainLoop() -{ - while (Tk_GetNumMainWindows() > 0) { - Tcl_DoOneEvent(0); - } -} diff --git a/generic/tkFileFilter.c b/generic/tkFileFilter.c deleted file mode 100644 index 6a8c54a..0000000 --- a/generic/tkFileFilter.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * tkFileFilter.c -- - * - * Process the -filetypes option for the file dialogs on Windows and the - * Mac. - * - * Copyright (c) 1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFileFilter.c,v 1.2 1998/09/14 18:23:10 stanton Exp $ - * - */ - -#include "tkInt.h" -#include "tkFileFilter.h" - -static int AddClause _ANSI_ARGS_(( - Tcl_Interp * interp, FileFilter * filterPtr, - char * patternsStr, char * ostypesStr, - int isWindows)); -static void FreeClauses _ANSI_ARGS_((FileFilter * filterPtr)); -static void FreeGlobPatterns _ANSI_ARGS_(( - FileFilterClause * clausePtr)); -static void FreeMacFileTypes _ANSI_ARGS_(( - FileFilterClause * clausePtr)); -static FileFilter * GetFilter _ANSI_ARGS_((FileFilterList * flistPtr, - char * name)); - -/* - *---------------------------------------------------------------------- - * - * TkInitFileFilters -- - * - * Initializes a FileFilterList data structure. A FileFilterList - * must be initialized EXACTLY ONCE before any calls to - * TkGetFileFilters() is made. The usual flow of control is: - * TkInitFileFilters(&flist); - * TkGetFileFilters(&flist, ...); - * TkGetFileFilters(&flist, ...); - * ... - * TkFreeFileFilters(&flist); - * - * Results: - * None. - * - * Side effects: - * The fields in flistPtr are initialized. - *---------------------------------------------------------------------- - */ - -void -TkInitFileFilters(flistPtr) - FileFilterList * flistPtr; /* The structure to be initialized. */ -{ - flistPtr->filters = NULL; - flistPtr->filtersTail = NULL; - flistPtr->numFilters = 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkGetFileFilters -- - * - * This function is called by the Mac and Windows implementation - * of tk_getOpenFile and tk_getSaveFile to translate the string - * value of the -filetypes option of into an easy-to-parse C - * structure (flistPtr). The caller of this function will then use - * flistPtr to perform filetype matching in a platform specific way. - * - * flistPtr must be initialized (See comments in TkInitFileFilters). - * - * Results: - * A standard TCL return value. - * - * Side effects: - * The fields in flistPtr are changed according to string. - *---------------------------------------------------------------------- - */ -int -TkGetFileFilters(interp, flistPtr, string, isWindows) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - FileFilterList * flistPtr; /* Stores the list of file filters. */ - char * string; /* Value of the -filetypes option. */ - int isWindows; /* True if we are running on Windows. */ -{ - int listArgc; - char ** listArgv = NULL; - char ** typeInfo = NULL; - int code = TCL_OK; - int i; - - if (Tcl_SplitList(interp, string, &listArgc, &listArgv) != TCL_OK) { - return TCL_ERROR; - } - if (listArgc == 0) { - goto done; - } - - /* - * Free the filter information that have been allocated the previous - * time -- the -filefilters option may have been used more than once in - * the command line. - */ - TkFreeFileFilters(flistPtr); - - for (i = 0; i<listArgc; i++) { - /* - * Each file type should have two or three elements: the first one - * is the name of the type and the second is the filter of the type. - * The third is the Mac OSType ID, but we don't care about them here. - */ - int count; - FileFilter * filterPtr; - - if (Tcl_SplitList(interp, listArgv[i], &count, &typeInfo) != TCL_OK) { - code = TCL_ERROR; - goto done; - } - - if (count != 2 && count != 3) { - Tcl_AppendResult(interp, "bad file type \"", listArgv[i], "\", ", - "should be \"typeName {extension ?extensions ...?} ", - "?{macType ?macTypes ...?}?\"", NULL); - code = TCL_ERROR; - goto done; - } - - filterPtr = GetFilter(flistPtr, typeInfo[0]); - - if (count == 2) { - code = AddClause(interp, filterPtr, typeInfo[1], NULL, - isWindows); - } else { - code = AddClause(interp, filterPtr, typeInfo[1], typeInfo[2], - isWindows); - } - if (code != TCL_OK) { - goto done; - } - - if (typeInfo) { - ckfree((char*)typeInfo); - } - typeInfo = NULL; - } - - done: - if (typeInfo) { - ckfree((char*)typeInfo); - } - if (listArgv) { - ckfree((char*)listArgv); - } - return code; -} - -/* - *---------------------------------------------------------------------- - * - * TkFreeFileFilters -- - * - * Frees the malloc'ed file filter information. - * - * Results: - * None. - * - * Side effects: - * The fields allocated by TkGetFileFilters() are freed. - *---------------------------------------------------------------------- - */ - -void -TkFreeFileFilters(flistPtr) - FileFilterList * flistPtr; /* List of file filters to free */ -{ - FileFilter * filterPtr, *toFree; - - filterPtr=flistPtr->filters; - while (filterPtr) { - toFree = filterPtr; - filterPtr=filterPtr->next; - FreeClauses(toFree); - ckfree((char*)toFree->name); - ckfree((char*)toFree); - } - flistPtr->filters = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * AddClause -- - * - * Add one FileFilterClause to filterPtr. - * - * Results: - * A standard TCL result. - * - * Side effects: - * The list of filter clauses are updated in filterPtr. - *---------------------------------------------------------------------- - */ - -static int AddClause(interp, filterPtr, patternsStr, ostypesStr, isWindows) - Tcl_Interp * interp; /* Interpreter to use for error reporting. */ - FileFilter * filterPtr; /* Stores the new filter clause */ - char * patternsStr; /* A TCL list of glob patterns. */ - char * ostypesStr; /* A TCL list of Mac OSType strings. */ - int isWindows; /* True if we are running on Windows; False - * if we are running on the Mac; Glob - * patterns need to be processed differently - * on these two platforms */ -{ - char ** globList = NULL; - int globCount; - char ** ostypeList = NULL; - int ostypeCount; - FileFilterClause * clausePtr; - int i; - int code = TCL_OK; - - if (Tcl_SplitList(interp, patternsStr, &globCount, &globList)!= TCL_OK) { - code = TCL_ERROR; - goto done; - } - if (ostypesStr != NULL) { - if (Tcl_SplitList(interp, ostypesStr, &ostypeCount, &ostypeList) - != TCL_OK) { - code = TCL_ERROR; - goto done; - } - for (i=0; i<ostypeCount; i++) { - if (strlen(ostypeList[i]) != 4) { - Tcl_AppendResult(interp, "bad Macintosh file type \"", - ostypeList[i], "\"", NULL); - code = TCL_ERROR; - goto done; - } - } - } - - /* - * Add the clause into the list of clauses - */ - - clausePtr = (FileFilterClause*)ckalloc(sizeof(FileFilterClause)); - clausePtr->patterns = NULL; - clausePtr->patternsTail = NULL; - clausePtr->macTypes = NULL; - clausePtr->macTypesTail = NULL; - - if (filterPtr->clauses == NULL) { - filterPtr->clauses = filterPtr->clausesTail = clausePtr; - } else { - filterPtr->clausesTail->next = clausePtr; - filterPtr->clausesTail = clausePtr; - } - clausePtr->next = NULL; - - if (globCount > 0 && globList != NULL) { - for (i=0; i<globCount; i++) { - GlobPattern * globPtr = (GlobPattern*)ckalloc(sizeof(GlobPattern)); - int len; - - len = (strlen(globList[i]) + 1) * sizeof(char); - - if (globList[i][0] && globList[i][0] != '*') { - /* - * Prepend a "*" to patterns that do not have a leading "*" - */ - globPtr->pattern = (char*)ckalloc(len+1); - globPtr->pattern[0] = '*'; - strcpy(globPtr->pattern+1, globList[i]); - } - else if (isWindows) { - if (strcmp(globList[i], "*") == 0) { - globPtr->pattern = (char*)ckalloc(4*sizeof(char)); - strcpy(globPtr->pattern, "*.*"); - } - else if (strcmp(globList[i], "") == 0) { - /* - * An empty string means "match all files with no - * extensions" - * BUG: "*." actually matches with all files on Win95 - */ - globPtr->pattern = (char*)ckalloc(3*sizeof(char)); - strcpy(globPtr->pattern, "*."); - } - else { - globPtr->pattern = (char*)ckalloc(len); - strcpy(globPtr->pattern, globList[i]); - } - } else { - globPtr->pattern = (char*)ckalloc(len); - strcpy(globPtr->pattern, globList[i]); - } - - /* - * Add the glob pattern into the list of patterns. - */ - - if (clausePtr->patterns == NULL) { - clausePtr->patterns = clausePtr->patternsTail = globPtr; - } else { - clausePtr->patternsTail->next = globPtr; - clausePtr->patternsTail = globPtr; - } - globPtr->next = NULL; - } - } - if (ostypeCount > 0 && ostypeList != NULL) { - for (i=0; i<ostypeCount; i++) { - MacFileType * mfPtr = (MacFileType*)ckalloc(sizeof(MacFileType)); - - memcpy(&mfPtr->type, ostypeList[i], sizeof(OSType)); - - /* - * Add the Mac type pattern into the list of Mac types - */ - if (clausePtr->macTypes == NULL) { - clausePtr->macTypes = clausePtr->macTypesTail = mfPtr; - } else { - clausePtr->macTypesTail->next = mfPtr; - clausePtr->macTypesTail = mfPtr; - } - mfPtr->next = NULL; - } - } - - done: - if (globList) { - ckfree((char*)globList); - } - if (ostypeList) { - ckfree((char*)ostypeList); - } - - return code; -} - -/* - *---------------------------------------------------------------------- - * - * GetFilter -- - * - * Add one FileFilter to flistPtr. - * - * Results: - * A standard TCL result. - * - * Side effects: - * The list of filters are updated in flistPtr. - *---------------------------------------------------------------------- - */ - -static FileFilter * GetFilter(flistPtr, name) - FileFilterList * flistPtr; /* The FileFilterList that contains the - * newly created filter */ - char * name; /* Name of the filter. It is usually displayed - * in the "File Types" listbox in the file - * dialogs. */ -{ - FileFilter * filterPtr; - - for (filterPtr=flistPtr->filters; filterPtr; filterPtr=filterPtr->next) { - if (strcmp(filterPtr->name, name)==0) { - return filterPtr; - } - } - - filterPtr = (FileFilter*)ckalloc(sizeof(FileFilter)); - filterPtr->clauses = NULL; - filterPtr->clausesTail = NULL; - filterPtr->name = (char*)ckalloc((strlen(name)+1) * sizeof(char)); - strcpy(filterPtr->name, name); - - if (flistPtr->filters == NULL) { - flistPtr->filters = flistPtr->filtersTail = filterPtr; - } else { - flistPtr->filtersTail->next = filterPtr; - flistPtr->filtersTail = filterPtr; - } - filterPtr->next = NULL; - - ++flistPtr->numFilters; - return filterPtr; -} - -/* - *---------------------------------------------------------------------- - * - * FreeClauses -- - * - * Frees the malloc'ed file type clause - * - * Results: - * None. - * - * Side effects: - * The list of clauses in filterPtr->clauses are freed. - *---------------------------------------------------------------------- - */ - -static void -FreeClauses(filterPtr) - FileFilter * filterPtr; /* FileFilter whose clauses are to be freed */ -{ - FileFilterClause * clausePtr, * toFree; - - clausePtr = filterPtr->clauses; - while (clausePtr) { - toFree = clausePtr; - clausePtr=clausePtr->next; - FreeGlobPatterns(toFree); - FreeMacFileTypes(toFree); - ckfree((char*)toFree); - } - filterPtr->clauses = NULL; - filterPtr->clausesTail = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * FreeGlobPatterns -- - * - * Frees the malloc'ed glob patterns in a clause - * - * Results: - * None. - * - * Side effects: - * The list of glob patterns in clausePtr->patterns are freed. - *---------------------------------------------------------------------- - */ - -static void -FreeGlobPatterns(clausePtr) - FileFilterClause * clausePtr;/* The clause whose patterns are to be freed*/ -{ - GlobPattern * globPtr, * toFree; - - globPtr = clausePtr->patterns; - while (globPtr) { - toFree = globPtr; - globPtr=globPtr->next; - - ckfree((char*)toFree->pattern); - ckfree((char*)toFree); - } - clausePtr->patterns = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * FreeMacFileTypes -- - * - * Frees the malloc'ed Mac file types in a clause - * - * Results: - * None. - * - * Side effects: - * The list of Mac file types in clausePtr->macTypes are freed. - *---------------------------------------------------------------------- - */ - -static void -FreeMacFileTypes(clausePtr) - FileFilterClause * clausePtr; /* The clause whose mac types are to be - * freed */ -{ - MacFileType * mfPtr, * toFree; - - mfPtr = clausePtr->macTypes; - while (mfPtr) { - toFree = mfPtr; - mfPtr=mfPtr->next; - ckfree((char*)toFree); - } - clausePtr->macTypes = NULL; -} diff --git a/generic/tkFileFilter.h b/generic/tkFileFilter.h deleted file mode 100644 index e1bc763..0000000 --- a/generic/tkFileFilter.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * tkFileFilter.h -- - * - * Declarations for the file filter processing routines needed by - * the file selection dialogs. - * - * Copyright (c) 1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFileFilter.h,v 1.4 1998/09/14 18:23:10 stanton Exp $ - * - */ - -#ifndef _TK_FILE_FILTER -#define _TK_FILE_FILTER - -#ifdef MAC_TCL -#include <StandardFile.h> -#else -#define OSType long -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -typedef struct GlobPattern { - struct GlobPattern * next; /* Chains to the next glob pattern - * in a glob pattern list */ - char * pattern; /* String value of the pattern, such - * as "*.txt" or "*.*" - */ -} GlobPattern; - -typedef struct MacFileType { - struct MacFileType * next; /* Chains to the next mac file type - * in a mac file type list */ - OSType type; /* Mac file type, such as 'TEXT' or - * 'GIFF' */ -} MacFileType; - -typedef struct FileFilterClause { - struct FileFilterClause * next; /* Chains to the next clause in - * a clause list */ - GlobPattern * patterns; /* Head of glob pattern type list */ - GlobPattern * patternsTail; /* Tail of glob pattern type list */ - MacFileType * macTypes; /* Head of mac file type list */ - MacFileType * macTypesTail; /* Tail of mac file type list */ -} FileFilterClause; - -typedef struct FileFilter { - struct FileFilter * next; /* Chains to the next filter - * in a filter list */ - char * name; /* Name of the file filter, - * such as "Text Documents" */ - FileFilterClause * clauses; /* Head of the clauses list */ - FileFilterClause * clausesTail; /* Tail of the clauses list */ -} FileFilter; - -/*---------------------------------------------------------------------- - * FileFilterList -- - * - * The routine TkGetFileFilters() translates the string value of the - * -filefilters option into a FileFilterList structure, which consists - * of a list of file filters. - * - * Each file filter consists of one or more clauses. Each clause has - * one or more glob patterns and/or one or more Mac file types - *---------------------------------------------------------------------- - */ - -typedef struct FileFilterList { - FileFilter * filters; /* Head of the filter list */ - FileFilter * filtersTail; /* Tail of the filter list */ - int numFilters; /* number of filters in the list */ -} FileFilterList; - -EXTERN void TkFreeFileFilters _ANSI_ARGS_(( - FileFilterList * flistPtr)); -EXTERN void TkInitFileFilters _ANSI_ARGS_(( - FileFilterList * flistPtr)); -EXTERN int TkGetFileFilters _ANSI_ARGS_ ((Tcl_Interp *interp, - FileFilterList * flistPtr, char * string, - int isWindows)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif diff --git a/generic/tkFocus.c b/generic/tkFocus.c deleted file mode 100644 index 75c10bb..0000000 --- a/generic/tkFocus.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * tkFocus.c -- - * - * This file contains procedures that manage the input - * focus for Tk. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFocus.c,v 1.2 1998/09/14 18:23:10 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - - -/* - * For each top-level window that has ever received the focus, there - * is a record of the following type: - */ - -typedef struct TkToplevelFocusInfo { - TkWindow *topLevelPtr; /* Information about top-level window. */ - TkWindow *focusWinPtr; /* The next time the focus comes to this - * top-level, it will be given to this - * window. */ - struct TkToplevelFocusInfo *nextPtr; - /* Next in list of all toplevel focus records - * for a given application. */ -} ToplevelFocusInfo; - -/* - * One of the following structures exists for each display used by - * each application. These are linked together from the TkMainInfo - * structure. These structures are needed because it isn't - * sufficient to store a single piece of focus information in each - * display or in each application: we need the cross-product. - * There needs to be separate information for each display, because - * it's possible to have multiple focus windows active simultaneously - * on different displays. There also needs to be separate information - * for each application, because of embedding: if an embedded - * application has the focus, its container application also has - * the focus. Thus we keep a list of structures for each application: - * the same display can appear in structures for several applications - * at once. - */ - -typedef struct TkDisplayFocusInfo { - TkDisplay *dispPtr; /* Display that this information pertains - * to. */ - struct TkWindow *focusWinPtr; - /* Window that currently has the focus for - * this application on this display, or NULL - * if none. */ - struct TkWindow *focusOnMapPtr; - /* This points to a toplevel window that is - * supposed to receive the X input focus as - * soon as it is mapped (needed to handle the - * fact that X won't allow the focus on an - * unmapped window). NULL means no delayed - * focus op in progress for this display. */ - int forceFocus; /* Associated with focusOnMapPtr: non-zero - * means claim the focus even if some other - * application currently has it. */ - unsigned long focusSerial; /* Serial number of last request this - * application made to change the focus on - * this display. Used to identify stale - * focus notifications coming from the - * X server. */ - struct TkDisplayFocusInfo *nextPtr; - /* Next in list of all display focus - * records for a given application. */ -} DisplayFocusInfo; - -/* - * Global used for debugging. - */ - -int tclFocusDebug = 0; - -/* - * The following magic value is stored in the "send_event" field of - * FocusIn and FocusOut events that are generated in this file. This - * allows us to separate "real" events coming from the server from - * those that we generated. - */ - -#define GENERATED_EVENT_MAGIC ((Bool) 0x547321ac) - -/* - * Forward declarations for procedures defined in this file: - */ - - -static DisplayFocusInfo *FindDisplayFocusInfo _ANSI_ARGS_((TkMainInfo *mainPtr, - TkDisplay *dispPtr)); -static void FocusMapProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr, - TkWindow *destPtr)); -static void SetFocus _ANSI_ARGS_((TkWindow *winPtr, int force)); - -/* - *-------------------------------------------------------------- - * - * Tk_FocusCmd -- - * - * This procedure is invoked to process the "focus" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_FocusCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - TkWindow *winPtr = (TkWindow *) clientData; - TkWindow *newPtr, *focusWinPtr, *topLevelPtr; - ToplevelFocusInfo *tlFocusPtr; - char c; - size_t length; - - /* - * If invoked with no arguments, just return the current focus window. - */ - - if (argc == 1) { - focusWinPtr = TkGetFocusWin(winPtr); - if (focusWinPtr != NULL) { - interp->result = focusWinPtr->pathName; - } - return TCL_OK; - } - - /* - * If invoked with a single argument beginning with "." then focus - * on that window. - */ - - if (argc == 2) { - if (argv[1][0] == 0) { - return TCL_OK; - } - if (argv[1][0] == '.') { - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - if (!(newPtr->flags & TK_ALREADY_DEAD)) { - SetFocus(newPtr, 0); - } - return TCL_OK; - } - } - - length = strlen(argv[1]); - c = argv[1][1]; - if ((c == 'd') && (strncmp(argv[1], "-displayof", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -displayof window\"", (char *) NULL); - return TCL_ERROR; - } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - newPtr = TkGetFocusWin(newPtr); - if (newPtr != NULL) { - interp->result = newPtr->pathName; - } - } else if ((c == 'f') && (strncmp(argv[1], "-force", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -force window\"", (char *) NULL); - return TCL_ERROR; - } - if (argv[2][0] == 0) { - return TCL_OK; - } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - SetFocus(newPtr, 1); - } else if ((c == 'l') && (strncmp(argv[1], "-lastfor", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -lastfor window\"", (char *) NULL); - return TCL_ERROR; - } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - for (topLevelPtr = newPtr; topLevelPtr != NULL; - topLevelPtr = topLevelPtr->parentPtr) { - if (topLevelPtr->flags & TK_TOP_LEVEL) { - for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; - tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == topLevelPtr) { - interp->result = tlFocusPtr->focusWinPtr->pathName; - return TCL_OK; - } - } - interp->result = topLevelPtr->pathName; - return TCL_OK; - } - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be -displayof, -force, or -lastfor", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkFocusFilterEvent -- - * - * This procedure is invoked by Tk_HandleEvent when it encounters - * a FocusIn, FocusOut, Enter, or Leave event. - * - * Results: - * A return value of 1 means that Tk_HandleEvent should process - * the event normally (i.e. event handlers should be invoked). - * A return value of 0 means that this event should be ignored. - * - * Side effects: - * Additional events may be generated, and the focus may switch. - * - *-------------------------------------------------------------- - */ - -int -TkFocusFilterEvent(winPtr, eventPtr) - TkWindow *winPtr; /* Window that focus event is directed to. */ - XEvent *eventPtr; /* FocusIn, FocusOut, Enter, or Leave - * event. */ -{ - /* - * Design notes: the window manager and X server work together to - * transfer the focus among top-level windows. This procedure takes - * care of transferring the focus from a top-level or wrapper window - * to the actual window within that top-level that has the focus. - * We do this by synthesizing X events to move the focus around. - * None of the FocusIn and FocusOut events generated by X are ever - * used outside of this procedure; only the synthesized events get - * through to the rest of the application. At one point (e.g. - * Tk4.0b1) Tk used to call X to move the focus from a top-level to - * one of its descendants, then just pass through the events - * generated by X. This approach didn't work very well, for a - * variety of reasons. For example, if X generates the events they - * go at the back of the event queue, which could cause problems if - * other things have already happened, such as moving the focus to - * yet another window. - */ - - ToplevelFocusInfo *tlFocusPtr; - DisplayFocusInfo *displayFocusPtr; - TkDisplay *dispPtr = winPtr->dispPtr; - TkWindow *newFocusPtr; - int retValue, delta; - - /* - * If this was a generated event, just turn off the generated - * flag and pass the event through to Tk bindings. - */ - - if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) { - eventPtr->xfocus.send_event = 0; - return 1; - } - - /* - * Check for special events generated by embedded applications to - * request the input focus. If this is one of those events, make - * the change in focus and return without any additional processing - * of the event (note: the "detail" field of the event indicates - * whether to claim the focus even if we don't already have it). - */ - - if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS) - && (eventPtr->type == FocusIn)) { - SetFocus(winPtr, eventPtr->xfocus.detail); - return 0; - } - - /* - * This was not a generated event. We'll return 1 (so that the - * event will be processed) if it's an Enter or Leave event, and - * 0 (so that the event won't be processed) if it's a FocusIn or - * FocusOut event. - */ - - retValue = 0; - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - if (eventPtr->type == FocusIn) { - /* - * Skip FocusIn events that cause confusion - * NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur - * on windows in between the origin and destination of the - * focus change. For FocusIn we may see this when focus - * goes into an embedded child. We don't care about this, - * although we may end up getting a NotifyPointer later. - * NotifyInferior - focus is coming to us from an embedded child. - * When focus is on an embeded focus, we still think we have - * the focus, too, so this message doesn't change our state. - * NotifyPointerRoot - should never happen because this is sent - * to the root window. - * - * Interesting FocusIn events are - * NotifyAncestor - focus is coming from our parent, probably the root. - * NotifyNonlinear - focus is coming from a different branch, probably - * another toplevel. - * NotifyPointer - implicit focus because of the mouse position. - * This is only interesting on toplevels, when it means that the - * focus has been set to the root window but the mouse is over - * this toplevel. We take the focus implicitly (probably no - * window manager) - */ - - if ((eventPtr->xfocus.detail == NotifyVirtual) - || (eventPtr->xfocus.detail == NotifyNonlinearVirtual) - || (eventPtr->xfocus.detail == NotifyPointerRoot) - || (eventPtr->xfocus.detail == NotifyInferior)) { - return retValue; - } - } else if (eventPtr->type == FocusOut) { - /* - * Skip FocusOut events that cause confusion. - * NotifyPointer - the pointer is in us or a child, and we are losing - * focus because of an XSetInputFocus. Other focus events - * will set our state properly. - * NotifyPointerRoot - should never happen because this is sent - * to the root window. - * NotifyInferior - focus leaving us for an embedded child. We - * retain a notion of focus when an embedded child has focus. - * - * Interesting events are: - * NotifyAncestor - focus is going to root. - * NotifyNonlinear - focus is going to another branch, probably - * another toplevel. - * NotifyVirtual, NotifyNonlinearVirtual - focus is passing through, - * and we need to make sure we track this. - */ - - if ((eventPtr->xfocus.detail == NotifyPointer) - || (eventPtr->xfocus.detail == NotifyPointerRoot) - || (eventPtr->xfocus.detail == NotifyInferior)) { - return retValue; - } - } else { - retValue = 1; - if (eventPtr->xcrossing.detail == NotifyInferior) { - return retValue; - } - } - - /* - * If winPtr isn't a top-level window than just ignore the event. - */ - - winPtr = TkWmFocusToplevel(winPtr); - if (winPtr == NULL) { - return retValue; - } - - /* - * If there is a grab in effect and this window is outside the - * grabbed tree, then ignore the event. - */ - - if (TkGrabState(winPtr) == TK_GRAB_EXCLUDED) { - return retValue; - } - - /* - * It is possible that there were outstanding FocusIn and FocusOut - * events on their way to us at the time the focus was changed - * internally with the "focus" command. If so, these events could - * potentially cause us to lose the focus (switch it to the window - * of the last FocusIn event) even though the focus change occurred - * after those events. The following code detects this and ignores - * the stale events. - * - * Note: the focusSerial is only generated by TkpChangeFocus, - * whereas in Tk 4.2 there was always a nop marker generated. - */ - - delta = eventPtr->xfocus.serial - displayFocusPtr->focusSerial; - if (delta < 0) { - return retValue; - } - - /* - * Find the ToplevelFocusInfo structure for the window, and make a new one - * if there isn't one already. - */ - - for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == winPtr) { - break; - } - } - if (tlFocusPtr == NULL) { - tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo)); - tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr; - tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr; - winPtr->mainPtr->tlFocusPtr = tlFocusPtr; - } - newFocusPtr = tlFocusPtr->focusWinPtr; - - if (eventPtr->type == FocusIn) { - GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr); - displayFocusPtr->focusWinPtr = newFocusPtr; - dispPtr->focusPtr = newFocusPtr; - - /* - * NotifyPointer gets set when the focus has been set to the root window - * but we have the pointer. We'll treat this like an implicit - * focus in event so that upon Leave events we release focus. - */ - - if (!(winPtr->flags & TK_EMBEDDED)) { - if (eventPtr->xfocus.detail == NotifyPointer) { - dispPtr->implicitWinPtr = winPtr; - } else { - dispPtr->implicitWinPtr = NULL; - } - } - } else if (eventPtr->type == FocusOut) { - GenerateFocusEvents(displayFocusPtr->focusWinPtr, (TkWindow *) NULL); - - /* - * Reset dispPtr->focusPtr, but only if it currently is the same - * as this application's focusWinPtr: this check is needed to - * handle embedded applications in the same process. - */ - - if (dispPtr->focusPtr == displayFocusPtr->focusWinPtr) { - dispPtr->focusPtr = NULL; - } - displayFocusPtr->focusWinPtr = NULL; - } else if (eventPtr->type == EnterNotify) { - /* - * If there is no window manager, or if the window manager isn't - * moving the focus around (e.g. the disgusting "NoTitleFocus" - * option has been selected in twm), then we won't get FocusIn - * or FocusOut events. Instead, the "focus" field will be set - * in an Enter event to indicate that we've already got the focus - * when the mouse enters the window (even though we didn't get - * a FocusIn event). Watch for this and grab the focus when it - * happens. Note: if this is an embedded application then don't - * accept the focus implicitly like this; the container - * application will give us the focus explicitly if it wants us - * to have it. - */ - - if (eventPtr->xcrossing.focus && - (displayFocusPtr->focusWinPtr == NULL) - && !(winPtr->flags & TK_EMBEDDED)) { - if (tclFocusDebug) { - printf("Focussed implicitly on %s\n", - newFocusPtr->pathName); - } - - GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr); - displayFocusPtr->focusWinPtr = newFocusPtr; - dispPtr->implicitWinPtr = winPtr; - dispPtr->focusPtr = newFocusPtr; - } - } else if (eventPtr->type == LeaveNotify) { - /* - * If the pointer just left a window for which we automatically - * claimed the focus on enter, move the focus back to the root - * window, where it was before we claimed it above. Note: - * dispPtr->implicitWinPtr may not be the same as - * displayFocusPtr->focusWinPtr (e.g. because the "focus" - * command was used to redirect the focus after it arrived at - * dispPtr->implicitWinPtr)!! In addition, we generate events - * because the window manager won't give us a FocusOut event when - * we focus on the root. - */ - - if ((dispPtr->implicitWinPtr != NULL) - && !(winPtr->flags & TK_EMBEDDED)) { - if (tclFocusDebug) { - printf("Defocussed implicit Async\n"); - } - GenerateFocusEvents(displayFocusPtr->focusWinPtr, - (TkWindow *) NULL); - XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot, - CurrentTime); - displayFocusPtr->focusWinPtr = NULL; - dispPtr->implicitWinPtr = NULL; - } - } - return retValue; -} - -/* - *---------------------------------------------------------------------- - * - * SetFocus -- - * - * This procedure is invoked to change the focus window for a - * given display in a given application. - * - * Results: - * None. - * - * Side effects: - * Event handlers may be invoked to process the change of - * focus. - * - *---------------------------------------------------------------------- - */ - -static void -SetFocus(winPtr, force) - TkWindow *winPtr; /* Window that is to be the new focus for - * its display and application. */ - int force; /* If non-zero, set the X focus to this - * window even if the application doesn't - * currently have the X focus. */ -{ - ToplevelFocusInfo *tlFocusPtr; - DisplayFocusInfo *displayFocusPtr; - TkWindow *topLevelPtr; - int allMapped, serial; - - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - if (winPtr == displayFocusPtr->focusWinPtr) { - return; - } - - /* - * Find the top-level window for winPtr, then find (or create) - * a record for the top-level. Also see whether winPtr and all its - * ancestors are mapped. - */ - - allMapped = 1; - for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr) { - if (topLevelPtr == NULL) { - /* - * The window is being deleted. No point in worrying about - * giving it the focus. - */ - return; - } - if (!(topLevelPtr->flags & TK_MAPPED)) { - allMapped = 0; - } - if (topLevelPtr->flags & TK_TOP_LEVEL) { - break; - } - } - - /* - * If the new focus window isn't mapped, then we can't focus on it - * (X will generate an error, for example). Instead, create an - * event handler that will set the focus to this window once it gets - * mapped. At the same time, delete any old handler that might be - * around; it's no longer relevant. - */ - - if (displayFocusPtr->focusOnMapPtr != NULL) { - Tk_DeleteEventHandler( - (Tk_Window) displayFocusPtr->focusOnMapPtr, - StructureNotifyMask, FocusMapProc, - (ClientData) displayFocusPtr->focusOnMapPtr); - displayFocusPtr->focusOnMapPtr = NULL; - } - if (!allMapped) { - Tk_CreateEventHandler((Tk_Window) winPtr, - VisibilityChangeMask, FocusMapProc, - (ClientData) winPtr); - displayFocusPtr->focusOnMapPtr = winPtr; - displayFocusPtr->forceFocus = force; - return; - } - - for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == topLevelPtr) { - break; - } - } - if (tlFocusPtr == NULL) { - tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo)); - tlFocusPtr->topLevelPtr = topLevelPtr; - tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr; - winPtr->mainPtr->tlFocusPtr = tlFocusPtr; - } - tlFocusPtr->focusWinPtr = winPtr; - - /* - * Reset the window system's focus window and generate focus events, - * with two special cases: - * - * 1. If the application is embedded and doesn't currently have the - * focus, don't set the focus directly. Instead, see if the - * embedding code can claim the focus from the enclosing - * container. - * 2. Otherwise, if the application doesn't currently have the - * focus, don't change the window system's focus unless it was - * already in this application or "force" was specified. - */ - - if ((topLevelPtr->flags & TK_EMBEDDED) - && (displayFocusPtr->focusWinPtr == NULL)) { - TkpClaimFocus(topLevelPtr, force); - } else if ((displayFocusPtr->focusWinPtr != NULL) || force) { - /* - * Generate events to shift focus between Tk windows. - * We do this regardless of what TkpChangeFocus does with - * the real X focus so that Tk widgets track focus commands - * when there is no window manager. GenerateFocusEvents will - * set up a serial number marker so we discard focus events - * that are triggered by the ChangeFocus. - */ - - serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force); - if (serial != 0) { - displayFocusPtr->focusSerial = serial; - } - GenerateFocusEvents(displayFocusPtr->focusWinPtr, winPtr); - displayFocusPtr->focusWinPtr = winPtr; - winPtr->dispPtr->focusPtr = winPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkGetFocusWin -- - * - * Given a window, this procedure returns the current focus - * window for its application and display. - * - * Results: - * The return value is a pointer to the window that currently - * has the input focus for the specified application and - * display, or NULL if none. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkWindow * -TkGetFocusWin(winPtr) - TkWindow *winPtr; /* Window that selects an application - * and a display. */ -{ - DisplayFocusInfo *displayFocusPtr; - - if (winPtr == NULL) { - return (TkWindow *) NULL; - } - - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - return displayFocusPtr->focusWinPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusKeyEvent -- - * - * Given a window and a key press or release event that arrived for - * the window, use information about the keyboard focus to compute - * which window should really get the event. In addition, update - * the event to refer to its new window. - * - * Results: - * The return value is a pointer to the window that has the input - * focus in winPtr's application, or NULL if winPtr's application - * doesn't have the input focus. If a non-NULL value is returned, - * eventPtr will be updated to refer properly to the focus window. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkWindow * -TkFocusKeyEvent(winPtr, eventPtr) - TkWindow *winPtr; /* Window that selects an application - * and a display. */ - XEvent *eventPtr; /* X event to redirect (should be KeyPress - * or KeyRelease). */ -{ - DisplayFocusInfo *displayFocusPtr; - TkWindow *focusWinPtr; - int focusX, focusY, vRootX, vRootY, vRootWidth, vRootHeight; - - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - focusWinPtr = displayFocusPtr->focusWinPtr; - - /* - * The code below is a debugging aid to make sure that dispPtr->focusPtr - * is kept properly in sync with the "truth", which is the value in - * displayFocusPtr->focusWinPtr. - */ - -#ifdef TCL_MEM_DEBUG - if (focusWinPtr != winPtr->dispPtr->focusPtr) { - printf("TkFocusKeyEvent found dispPtr->focusPtr out of sync:\n"); - printf("expected %s, got %s\n", - (focusWinPtr != NULL) ? focusWinPtr->pathName : "??", - (winPtr->dispPtr->focusPtr != NULL) ? - winPtr->dispPtr->focusPtr->pathName : "??"); - } -#endif - - if ((focusWinPtr != NULL) && (focusWinPtr->mainPtr == winPtr->mainPtr)) { - /* - * Map the x and y coordinates to make sense in the context of - * the focus window, if possible (make both -1 if the map-from - * and map-to windows don't share the same screen). - */ - - if ((focusWinPtr->display != winPtr->display) - || (focusWinPtr->screenNum != winPtr->screenNum)) { - eventPtr->xkey.x = -1; - eventPtr->xkey.y = -1; - } else { - Tk_GetVRootGeometry((Tk_Window) focusWinPtr, &vRootX, &vRootY, - &vRootWidth, &vRootHeight); - Tk_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY); - eventPtr->xkey.x = eventPtr->xkey.x_root - vRootX - focusX; - eventPtr->xkey.y = eventPtr->xkey.y_root - vRootY - focusY; - } - eventPtr->xkey.window = focusWinPtr->window; - return focusWinPtr; - } - - /* - * The event doesn't belong to us. Perhaps, due to embedding, it - * really belongs to someone else. Give the embedding code a chance - * to redirect the event. - */ - - TkpRedirectKeyEvent(winPtr, eventPtr); - return (TkWindow *) NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusDeadWindow -- - * - * This procedure is invoked when it is determined that - * a window is dead. It cleans up focus-related information - * about the window. - * - * Results: - * None. - * - * Side effects: - * Various things get cleaned up and recycled. - * - *---------------------------------------------------------------------- - */ - -void -TkFocusDeadWindow(winPtr) - register TkWindow *winPtr; /* Information about the window - * that is being deleted. */ -{ - ToplevelFocusInfo *tlFocusPtr, *prevPtr; - DisplayFocusInfo *displayFocusPtr; - TkDisplay *dispPtr = winPtr->dispPtr; - - /* - * Search for focus records that refer to this window either as - * the top-level window or the current focus window. - */ - - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - for (prevPtr = NULL, tlFocusPtr = winPtr->mainPtr->tlFocusPtr; - tlFocusPtr != NULL; - prevPtr = tlFocusPtr, tlFocusPtr = tlFocusPtr->nextPtr) { - if (winPtr == tlFocusPtr->topLevelPtr) { - /* - * The top-level window is the one being deleted: free - * the focus record and release the focus back to PointerRoot - * if we acquired it implicitly. - */ - - if (dispPtr->implicitWinPtr == winPtr) { - if (tclFocusDebug) { - printf("releasing focus to root after %s died\n", - tlFocusPtr->topLevelPtr->pathName); - } - dispPtr->implicitWinPtr = NULL; - displayFocusPtr->focusWinPtr = NULL; - dispPtr->focusPtr = NULL; - } - if (displayFocusPtr->focusWinPtr == tlFocusPtr->focusWinPtr) { - displayFocusPtr->focusWinPtr = NULL; - dispPtr->focusPtr = NULL; - } - if (prevPtr == NULL) { - winPtr->mainPtr->tlFocusPtr = tlFocusPtr->nextPtr; - } else { - prevPtr->nextPtr = tlFocusPtr->nextPtr; - } - ckfree((char *) tlFocusPtr); - break; - } else if (winPtr == tlFocusPtr->focusWinPtr) { - /* - * The deleted window had the focus for its top-level: - * move the focus to the top-level itself. - */ - - tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr; - if ((displayFocusPtr->focusWinPtr == winPtr) - && !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) { - if (tclFocusDebug) { - printf("forwarding focus to %s after %s died\n", - tlFocusPtr->topLevelPtr->pathName, - winPtr->pathName); - } - GenerateFocusEvents(displayFocusPtr->focusWinPtr, - tlFocusPtr->topLevelPtr); - displayFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr; - dispPtr->focusPtr = tlFocusPtr->topLevelPtr; - } - break; - } - } - - if (displayFocusPtr->focusOnMapPtr == winPtr) { - displayFocusPtr->focusOnMapPtr = NULL; - } -} - -/* - *---------------------------------------------------------------------- - * - * GenerateFocusEvents -- - * - * This procedure is called to create FocusIn and FocusOut events to - * move the input focus from one window to another. - * - * Results: - * None. - * - * Side effects: - * FocusIn and FocusOut events are generated. - * - *---------------------------------------------------------------------- - */ - -static void -GenerateFocusEvents(sourcePtr, destPtr) - TkWindow *sourcePtr; /* Window that used to have the focus (may - * be NULL). */ - TkWindow *destPtr; /* New window to have the focus (may be - * NULL). */ - -{ - XEvent event; - TkWindow *winPtr; - - winPtr = sourcePtr; - if (winPtr == NULL) { - winPtr = destPtr; - if (winPtr == NULL) { - return; - } - } - - event.xfocus.serial = LastKnownRequestProcessed(winPtr->display); - event.xfocus.send_event = GENERATED_EVENT_MAGIC; - event.xfocus.display = winPtr->display; - event.xfocus.mode = NotifyNormal; - TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn, - TCL_QUEUE_MARK); -} - -/* - *---------------------------------------------------------------------- - * - * FocusMapProc -- - * - * This procedure is called as an event handler for VisibilityNotify - * events, if a window receives the focus at a time when its - * toplevel isn't mapped. The procedure is needed because X - * won't allow the focus to be set to an unmapped window; we - * detect when the toplevel is mapped and set the focus to it then. - * - * Results: - * None. - * - * Side effects: - * If this is a map event, the focus gets set to the toplevel - * given by clientData. - * - *---------------------------------------------------------------------- - */ - -static void -FocusMapProc(clientData, eventPtr) - ClientData clientData; /* Toplevel window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkWindow *winPtr = (TkWindow *) clientData; - DisplayFocusInfo *displayFocusPtr; - - if (eventPtr->type == VisibilityNotify) { - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, - winPtr->dispPtr); - if (tclFocusDebug) { - printf("auto-focussing on %s, force %d\n", winPtr->pathName, - displayFocusPtr->forceFocus); - } - Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask, - FocusMapProc, clientData); - displayFocusPtr->focusOnMapPtr = NULL; - SetFocus(winPtr, displayFocusPtr->forceFocus); - } -} - -/* - *---------------------------------------------------------------------- - * - * FindDisplayFocusInfo -- - * - * Given an application and a display, this procedure locate the - * focus record for that combination. If no such record exists, - * it creates a new record and initializes it. - * - * Results: - * The return value is a pointer to the record. - * - * Side effects: - * A new record will be allocated if there wasn't one already. - * - *---------------------------------------------------------------------- - */ - -static DisplayFocusInfo * -FindDisplayFocusInfo(mainPtr, dispPtr) - TkMainInfo *mainPtr; /* Record that identifies a particular - * application. */ - TkDisplay *dispPtr; /* Display whose focus information is - * needed. */ -{ - DisplayFocusInfo *displayFocusPtr; - - for (displayFocusPtr = mainPtr->displayFocusPtr; - displayFocusPtr != NULL; - displayFocusPtr = displayFocusPtr->nextPtr) { - if (displayFocusPtr->dispPtr == dispPtr) { - return displayFocusPtr; - } - } - - /* - * The record doesn't exist yet. Make a new one. - */ - - displayFocusPtr = (DisplayFocusInfo *) ckalloc(sizeof(DisplayFocusInfo)); - displayFocusPtr->dispPtr = dispPtr; - displayFocusPtr->focusWinPtr = NULL; - displayFocusPtr->focusOnMapPtr = NULL; - displayFocusPtr->forceFocus = 0; - displayFocusPtr->focusSerial = 0; - displayFocusPtr->nextPtr = mainPtr->displayFocusPtr; - mainPtr->displayFocusPtr = displayFocusPtr; - return displayFocusPtr; -} diff --git a/generic/tkFont.c b/generic/tkFont.c deleted file mode 100644 index 4c0ebb9..0000000 --- a/generic/tkFont.c +++ /dev/null @@ -1,3008 +0,0 @@ -/* - * tkFont.c -- - * - * This file maintains a database of fonts for the Tk toolkit. - * It also provides several utility procedures for measuring and - * displaying text. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFont.c,v 1.2 1998/09/14 18:23:10 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkFont.h" - -/* - * The following structure is used to keep track of all the fonts that - * exist in the current application. It must be stored in the - * TkMainInfo for the application. - */ - -typedef struct TkFontInfo { - Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font. - * Keys are CachedFontKey structs, values are - * TkFont structs. */ - Tcl_HashTable namedTable; /* Map a name to a set of attributes for a - * font, used when constructing a Tk_Font from - * a named font description. Keys are - * Tk_Uids, values are NamedFont structs. */ - TkMainInfo *mainPtr; /* Application that owns this structure. */ - int updatePending; -} TkFontInfo; - -/* - * The following structure is used as a key in the fontCache. - */ - -typedef struct CachedFontKey { - Display *display; /* Display for which font was constructed. */ - Tk_Uid string; /* String that describes font. */ -} CachedFontKey; - -/* - * The following data structure is used to keep track of the font attributes - * for each named font that has been defined. The named font is only deleted - * when the last reference to it goes away. - */ - -typedef struct NamedFont { - int refCount; /* Number of users of named font. */ - int deletePending; /* Non-zero if font should be deleted when - * last reference goes away. */ - TkFontAttributes fa; /* Desired attributes for named font. */ -} NamedFont; - -/* - * The following two structures are used to keep track of string - * measurement information when using the text layout facilities. - * - * A LayoutChunk represents a contiguous range of text that can be measured - * and displayed by low-level text calls. In general, chunks will be - * delimited by newlines and tabs. Low-level, platform-specific things - * like kerning and non-integer character widths may occur between the - * characters in a single chunk, but not between characters in different - * chunks. - * - * A TextLayout is a collection of LayoutChunks. It can be displayed with - * respect to any origin. It is the implementation of the Tk_TextLayout - * opaque token. - */ - -typedef struct LayoutChunk { - CONST char *start; /* Pointer to simple string to be displayed. - * This is a pointer into the TkTextLayout's - * string. */ - int numChars; /* The number of characters in this chunk. */ - int numDisplayChars; /* The number of characters to display when - * this chunk is displayed. Can be less than - * numChars if extra space characters were - * absorbed by the end of the chunk. This - * will be < 0 if this is a chunk that is - * holding a tab or newline. */ - int x, y; /* The origin of the first character in this - * chunk with respect to the upper-left hand - * corner of the TextLayout. */ - int totalWidth; /* Width in pixels of this chunk. Used - * when hit testing the invisible spaces at - * the end of a chunk. */ - int displayWidth; /* Width in pixels of the displayable - * characters in this chunk. Can be less than - * width if extra space characters were - * absorbed by the end of the chunk. */ -} LayoutChunk; - -typedef struct TextLayout { - Tk_Font tkfont; /* The font used when laying out the text. */ - CONST char *string; /* The string that was layed out. */ - int width; /* The maximum width of all lines in the - * text layout. */ - int numChunks; /* Number of chunks actually used in - * following array. */ - LayoutChunk chunks[1]; /* Array of chunks. The actual size will - * be maxChunks. THIS FIELD MUST BE THE LAST - * IN THE STRUCTURE. */ -} TextLayout; - -/* - * The following structures are used as two-way maps between the values for - * the fields in the TkFontAttributes structure and the strings used in - * Tcl, when parsing both option-value format and style-list format font - * name strings. - */ - -static TkStateMap weightMap[] = { - {TK_FW_NORMAL, "normal"}, - {TK_FW_BOLD, "bold"}, - {TK_FW_UNKNOWN, NULL} -}; - -static TkStateMap slantMap[] = { - {TK_FS_ROMAN, "roman"}, - {TK_FS_ITALIC, "italic"}, - {TK_FS_UNKNOWN, NULL} -}; - -static TkStateMap underlineMap[] = { - {1, "underline"}, - {0, NULL} -}; - -static TkStateMap overstrikeMap[] = { - {1, "overstrike"}, - {0, NULL} -}; - -/* - * The following structures are used when parsing XLFD's into a set of - * TkFontAttributes. - */ - -static TkStateMap xlfdWeightMap[] = { - {TK_FW_NORMAL, "normal"}, - {TK_FW_NORMAL, "medium"}, - {TK_FW_NORMAL, "book"}, - {TK_FW_NORMAL, "light"}, - {TK_FW_BOLD, "bold"}, - {TK_FW_BOLD, "demi"}, - {TK_FW_BOLD, "demibold"}, - {TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */ -}; - -static TkStateMap xlfdSlantMap[] = { - {TK_FS_ROMAN, "r"}, - {TK_FS_ITALIC, "i"}, - {TK_FS_OBLIQUE, "o"}, - {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */ -}; - -static TkStateMap xlfdSetwidthMap[] = { - {TK_SW_NORMAL, "normal"}, - {TK_SW_CONDENSE, "narrow"}, - {TK_SW_CONDENSE, "semicondensed"}, - {TK_SW_CONDENSE, "condensed"}, - {TK_SW_UNKNOWN, NULL} -}; - -static TkStateMap xlfdCharsetMap[] = { - {TK_CS_NORMAL, "iso8859"}, - {TK_CS_SYMBOL, "adobe"}, - {TK_CS_SYMBOL, "sun"}, - {TK_CS_OTHER, NULL} -}; - -/* - * The following structure and defines specify the valid builtin options - * when configuring a set of font attributes. - */ - -static char *fontOpt[] = { - "-family", - "-size", - "-weight", - "-slant", - "-underline", - "-overstrike", - NULL -}; - -#define FONT_FAMILY 0 -#define FONT_SIZE 1 -#define FONT_WEIGHT 2 -#define FONT_SLANT 3 -#define FONT_UNDERLINE 4 -#define FONT_OVERSTRIKE 5 -#define FONT_NUMFIELDS 6 /* Length of fontOpt array. */ - -#define GetFontAttributes(tkfont) \ - ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa) - -#define GetFontMetrics(tkfont) \ - ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm) - - -static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[], - TkFontAttributes *faPtr)); -static int FieldSpecified _ANSI_ARGS_((CONST char *field)); -static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp, - CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr)); -static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr, - int *maxPtr, CONST char *start, int numChars, - int curX, int newX, int y)); -static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *objPtr, - TkFontAttributes *faPtr)); -static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr)); -static void TheWorldHasChanged _ANSI_ARGS_(( - ClientData clientData)); -static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr, - Tk_Window tkwin, Tcl_HashEntry *namedHashPtr)); - - - - -/* - *--------------------------------------------------------------------------- - * - * TkFontPkgInit -- - * - * This procedure is called when an application is created. It - * initializes all the structures that are used by the font - * package on a per application basis. - * - * Results: - * Returns a token that must be stored in the TkMainInfo for this - * application. - * - * Side effects: - * Memory allocated. - * - *--------------------------------------------------------------------------- - */ -void -TkFontPkgInit(mainPtr) - TkMainInfo *mainPtr; /* The application being created. */ -{ - TkFontInfo *fiPtr; - - fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo)); - Tcl_InitHashTable(&fiPtr->fontCache, sizeof(CachedFontKey) / sizeof(int)); - Tcl_InitHashTable(&fiPtr->namedTable, TCL_ONE_WORD_KEYS); - fiPtr->mainPtr = mainPtr; - fiPtr->updatePending = 0; - mainPtr->fontInfoPtr = fiPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * TkFontPkgFree -- - * - * This procedure is called when an application is deleted. It - * deletes all the structures that were used by the font package - * for this application. - * - * Results: - * None. - * - * Side effects: - * Memory freed. - * - *--------------------------------------------------------------------------- - */ - -void -TkFontPkgFree(mainPtr) - TkMainInfo *mainPtr; /* The application being deleted. */ -{ - TkFontInfo *fiPtr; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - - fiPtr = mainPtr->fontInfoPtr; - - if (fiPtr->fontCache.numEntries != 0) { - panic("TkFontPkgFree: all fonts should have been freed already"); - } - Tcl_DeleteHashTable(&fiPtr->fontCache); - - hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); - while (hPtr != NULL) { - ckfree((char *) Tcl_GetHashValue(hPtr)); - hPtr = Tcl_NextHashEntry(&search); - } - Tcl_DeleteHashTable(&fiPtr->namedTable); - if (fiPtr->updatePending != 0) { - Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr); - } - ckfree((char *) fiPtr); -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_FontObjCmd -- - * - * This procedure is implemented to process the "font" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_FontObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ -{ - int index; - Tk_Window tkwin; - TkFontInfo *fiPtr; - static char *optionStrings[] = { - "actual", "configure", "create", "delete", - "families", "measure", "metrics", "names", - NULL - }; - enum options { - FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE, - FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES - }; - - tkwin = (Tk_Window) clientData; - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); - return TCL_ERROR; - } - if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, - &index) != TCL_OK) { - return TCL_ERROR; - } - - switch ((enum options) index) { - case FONT_ACTUAL: { - int skip, result; - Tk_Font tkfont; - Tcl_Obj *objPtr; - CONST TkFontAttributes *faPtr; - - skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if ((objc < 3) || (objc - skip > 4)) { - Tcl_WrongNumArgs(interp, 2, objv, - "font ?-displayof window? ?option?"); - return TCL_ERROR; - } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); - if (tkfont == NULL) { - return TCL_ERROR; - } - objc -= skip; - objv += skip; - faPtr = GetFontAttributes(tkfont); - objPtr = NULL; - if (objc > 3) { - objPtr = objv[3]; - } - result = GetAttributeInfoObj(interp, faPtr, objPtr); - Tk_FreeFont(tkfont); - return result; - } - case FONT_CONFIGURE: { - int result; - char *string; - Tcl_Obj *objPtr; - NamedFont *nfPtr; - Tcl_HashEntry *namedHashPtr; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?"); - return TCL_ERROR; - } - string = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL)); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); - nfPtr = NULL; /* lint. */ - if (namedHashPtr != NULL) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - } - if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, - "\" doesn't exist", NULL); - return TCL_ERROR; - } - if (objc == 3) { - objPtr = NULL; - } else if (objc == 4) { - objPtr = objv[3]; - } else { - result = ConfigAttributesObj(interp, tkwin, objc - 3, - objv + 3, &nfPtr->fa); - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); - return result; - } - return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); - } - case FONT_CREATE: { - int skip, i; - char *name; - char buf[32]; - TkFontAttributes fa; - Tcl_HashEntry *namedHashPtr; - - skip = 3; - if (objc < 3) { - name = NULL; - } else { - name = Tcl_GetStringFromObj(objv[2], NULL); - if (name[0] == '-') { - name = NULL; - } - } - if (name == NULL) { - /* - * No font name specified. Generate one of the form "fontX". - */ - - for (i = 1; ; i++) { - sprintf(buf, "font%d", i); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, - Tk_GetUid(buf)); - if (namedHashPtr == NULL) { - break; - } - } - name = buf; - skip = 2; - } - TkInitFontAttributes(&fa); - if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip, - &fa) != TCL_OK) { - return TCL_ERROR; - } - if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); - break; - } - case FONT_DELETE: { - int i; - char *string; - NamedFont *nfPtr; - Tcl_HashEntry *namedHashPtr; - - /* - * Delete the named font. If there are still widgets using this - * font, then it isn't deleted right away. - */ - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?"); - return TCL_ERROR; - } - for (i = 2; i < objc; i++) { - string = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL)); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); - if (namedHashPtr == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->refCount != 0) { - nfPtr->deletePending = 1; - } else { - Tcl_DeleteHashEntry(namedHashPtr); - ckfree((char *) nfPtr); - } - } - break; - } - case FONT_FAMILIES: { - int skip; - - skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 2) { - Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?"); - return TCL_ERROR; - } - TkpGetFontFamilies(interp, tkwin); - break; - } - case FONT_MEASURE: { - char *string; - Tk_Font tkfont; - int length, skip; - - skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if (objc - skip != 4) { - Tcl_WrongNumArgs(interp, 2, objv, - "font ?-displayof window? text"); - return TCL_ERROR; - } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); - if (tkfont == NULL) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[3 + skip], &length); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_TextWidth(tkfont, string, length)); - Tk_FreeFont(tkfont); - break; - } - case FONT_METRICS: { - char buf[64]; - Tk_Font tkfont; - int skip, index, i; - CONST TkFontMetrics *fmPtr; - static char *switches[] = { - "-ascent", "-descent", "-linespace", "-fixed", NULL - }; - - skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); - if (skip < 0) { - return TCL_ERROR; - } - if ((objc < 3) || ((objc - skip) > 4)) { - Tcl_WrongNumArgs(interp, 2, objv, - "font ?-displayof window? ?option?"); - return TCL_ERROR; - } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); - if (tkfont == NULL) { - return TCL_ERROR; - } - objc -= skip; - objv += skip; - fmPtr = GetFontMetrics(tkfont); - if (objc == 3) { - sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d", - fmPtr->ascent, fmPtr->descent, - fmPtr->ascent + fmPtr->descent, - fmPtr->fixed); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); - } else { - if (Tcl_GetIndexFromObj(interp, objv[3], switches, - "metric", 0, &index) != TCL_OK) { - Tk_FreeFont(tkfont); - return TCL_ERROR; - } - i = 0; /* Needed only to prevent compiler - * warning. */ - switch (index) { - case 0: i = fmPtr->ascent; break; - case 1: i = fmPtr->descent; break; - case 2: i = fmPtr->ascent + fmPtr->descent; break; - case 3: i = fmPtr->fixed; break; - } - Tcl_SetIntObj(Tcl_GetObjResult(interp), i); - } - Tk_FreeFont(tkfont); - break; - } - case FONT_NAMES: { - char *string; - Tcl_Obj *strPtr; - NamedFont *nfPtr; - Tcl_HashSearch search; - Tcl_HashEntry *namedHashPtr; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "names"); - return TCL_ERROR; - } - namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); - while (namedHashPtr != NULL) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->deletePending == 0) { - string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr); - strPtr = Tcl_NewStringObj(string, -1); - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr); - } - namedHashPtr = Tcl_NextHashEntry(&search); - } - break; - } - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * UpdateDependantFonts, TheWorldHasChanged, RecomputeWidgets -- - * - * Called when the attributes of a named font changes. Updates all - * the instantiated fonts that depend on that named font and then - * uses the brute force approach and prepares every widget to - * recompute its geometry. - * - * Results: - * None. - * - * Side effects: - * Things get queued for redisplay. - * - *--------------------------------------------------------------------------- - */ - -static void -UpdateDependantFonts(fiPtr, tkwin, namedHashPtr) - TkFontInfo *fiPtr; /* Info about application's fonts. */ - Tk_Window tkwin; /* A window in the application. */ - Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */ -{ - Tcl_HashEntry *cacheHashPtr; - Tcl_HashSearch search; - TkFont *fontPtr; - NamedFont *nfPtr; - - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->refCount == 0) { - /* - * Well nobody's using this named font, so don't have to tell - * any widgets to recompute themselves. - */ - - return; - } - - - cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); - while (cacheHashPtr != NULL) { - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - if (fontPtr->namedHashPtr == namedHashPtr) { - TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); - if (fiPtr->updatePending == 0) { - fiPtr->updatePending = 1; - Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); - } - } - cacheHashPtr = Tcl_NextHashEntry(&search); - } -} - -static void -TheWorldHasChanged(clientData) - ClientData clientData; /* Info about application's fonts. */ -{ - TkFontInfo *fiPtr; - - fiPtr = (TkFontInfo *) clientData; - fiPtr->updatePending = 0; - - RecomputeWidgets(fiPtr->mainPtr->winPtr); -} - -static void -RecomputeWidgets(winPtr) - TkWindow *winPtr; /* Window to which command is sent. */ -{ - if ((winPtr->classProcsPtr != NULL) - && (winPtr->classProcsPtr->geometryProc != NULL)) { - (*winPtr->classProcsPtr->geometryProc)(winPtr->instanceData); - } - for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) { - RecomputeWidgets(winPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * TkCreateNamedFont -- - * - * Create the specified named font with the given attributes in the - * named font table associated with the interp. - * - * Results: - * Returns TCL_OK if the font was successfully created, or TCL_ERROR - * if the named font already existed. If TCL_ERROR is returned, an - * error message is left in interp->result. - * - * Side effects: - * Assume there used to exist a named font by the specified name, and - * that the named font had been deleted, but there were still some - * widgets using the named font at the time it was deleted. If a - * new named font is created with the same name, all those widgets - * that were using the old named font will be redisplayed using - * the new named font's attributes. - * - *--------------------------------------------------------------------------- - */ - -int -TkCreateNamedFont(interp, tkwin, name, faPtr) - Tcl_Interp *interp; /* Interp for error return. */ - Tk_Window tkwin; /* A window associated with interp. */ - CONST char *name; /* Name for the new named font. */ - TkFontAttributes *faPtr; /* Attributes for the new named font. */ -{ - TkFontInfo *fiPtr; - Tcl_HashEntry *namedHashPtr; - int new; - NamedFont *nfPtr; - - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - - name = Tk_GetUid(name); - namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new); - - if (new == 0) { - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - if (nfPtr->deletePending == 0) { - interp->result[0] = '\0'; - Tcl_AppendResult(interp, "font \"", name, - "\" already exists", (char *) NULL); - return TCL_ERROR; - } - - /* - * Recreating a named font with the same name as a previous - * named font. Some widgets were still using that named - * font, so they need to get redisplayed. - */ - - nfPtr->fa = *faPtr; - nfPtr->deletePending = 0; - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); - return TCL_OK; - } - - nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont)); - nfPtr->deletePending = 0; - Tcl_SetHashValue(namedHashPtr, nfPtr); - nfPtr->fa = *faPtr; - nfPtr->refCount = 0; - nfPtr->deletePending = 0; - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_GetFont -- - * - * Given a string description of a font, map the description to a - * corresponding Tk_Font that represents the font. - * - * Results: - * The return value is token for the font, or NULL if an error - * prevented the font from being created. If NULL is returned, an - * error message will be left in interp->result. - * - * Side effects: - * Calls Tk_GetFontFromObj(), which modifies interp's result object, - * then copies the string from the result object into interp->result. - * This procedure will go away when Tk_ConfigureWidget() is - * made into an object command. - * - *--------------------------------------------------------------------------- - */ - -Tk_Font -Tk_GetFont(interp, tkwin, string) - Tcl_Interp *interp; /* Interp for database and error return. */ - Tk_Window tkwin; /* For display on which font will be used. */ - CONST char *string; /* String describing font, as: named font, - * native format, or parseable string. */ -{ - Tcl_Obj *strPtr; - Tk_Font tkfont; - - strPtr = Tcl_NewStringObj((char *) string, -1); - - tkfont = Tk_GetFontFromObj(interp, tkwin, strPtr); - if (tkfont == NULL) { - Tcl_SetResult(interp, - Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL), - TCL_VOLATILE); - } - - Tcl_DecrRefCount(strPtr); /* done with object */ - return tkfont; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_GetFontFromObj -- - * - * Given a string description of a font, map the description to a - * corresponding Tk_Font that represents the font. - * - * Results: - * The return value is token for the font, or NULL if an error - * prevented the font from being created. If NULL is returned, an - * error message will be left in interp's result object. - * - * Side effects: - * The font is added to an internal database with a reference - * count. For each call to this procedure, there should eventually - * be a call to Tk_FreeFont() so that the database is cleaned up when - * fonts aren't in use anymore. - * - *--------------------------------------------------------------------------- - */ - -Tk_Font -Tk_GetFontFromObj(interp, tkwin, objPtr) - Tcl_Interp *interp; /* Interp for database and error return. */ - Tk_Window tkwin; /* For display on which font will be used. */ - Tcl_Obj *objPtr; /* Object describing font, as: named font, - * native format, or parseable string. */ -{ - TkFontInfo *fiPtr; - CachedFontKey key; - Tcl_HashEntry *cacheHashPtr, *namedHashPtr; - TkFont *fontPtr; - int new, descent; - NamedFont *nfPtr; - char *string; - - fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - string = Tcl_GetStringFromObj(objPtr, NULL); - - key.display = Tk_Display(tkwin); - key.string = Tk_GetUid(string); - cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, (char *) &key, &new); - - if (new == 0) { - /* - * We have already constructed a font with this description for - * this display. Bump the reference count of the cached font. - */ - - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - fontPtr->refCount++; - return (Tk_Font) fontPtr; - } - - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, key.string); - if (namedHashPtr != NULL) { - /* - * Construct a font based on a named font. - */ - - nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); - nfPtr->refCount++; - - fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa); - } else { - /* - * Native font? - */ - - fontPtr = TkpGetNativeFont(tkwin, string); - if (fontPtr == NULL) { - TkFontAttributes fa; - - TkInitFontAttributes(&fa); - if (ParseFontNameObj(interp, tkwin, objPtr, &fa) != TCL_OK) { - Tcl_DeleteHashEntry(cacheHashPtr); - return NULL; - } - - /* - * String contained the attributes inline. - */ - - fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa); - } - } - Tcl_SetHashValue(cacheHashPtr, fontPtr); - - fontPtr->refCount = 1; - fontPtr->cacheHashPtr = cacheHashPtr; - fontPtr->namedHashPtr = namedHashPtr; - - Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, 0, 0, &fontPtr->tabWidth); - if (fontPtr->tabWidth == 0) { - fontPtr->tabWidth = fontPtr->fm.maxWidth; - } - fontPtr->tabWidth *= 8; - - /* - * Make sure the tab width isn't zero (some fonts may not have enough - * information to set a reasonable tab width). - */ - - if (fontPtr->tabWidth == 0) { - fontPtr->tabWidth = 1; - } - - /* - * Get information used for drawing underlines in generic code on a - * non-underlined font. - */ - - descent = fontPtr->fm.descent; - fontPtr->underlinePos = descent / 2; - fontPtr->underlineHeight = fontPtr->fa.pointsize / 10; - if (fontPtr->underlineHeight == 0) { - fontPtr->underlineHeight = 1; - } - if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) { - /* - * If this set of values would cause the bottom of the underline - * bar to stick below the descent of the font, jack the underline - * up a bit higher. - */ - - fontPtr->underlineHeight = descent - fontPtr->underlinePos; - if (fontPtr->underlineHeight == 0) { - fontPtr->underlinePos--; - fontPtr->underlineHeight = 1; - } - } - - return (Tk_Font) fontPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_NameOfFont -- - * - * Given a font, return a textual string identifying it. - * - * Results: - * The return value is the description that was passed to - * Tk_GetFont() to create the font. The storage for the returned - * string is only guaranteed to persist until the font is deleted. - * The caller should not modify this string. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -char * -Tk_NameOfFont(tkfont) - Tk_Font tkfont; /* Font whose name is desired. */ -{ - TkFont *fontPtr; - Tcl_HashEntry *hPtr; - CachedFontKey *keyPtr; - - fontPtr = (TkFont *) tkfont; - hPtr = fontPtr->cacheHashPtr; - - keyPtr = (CachedFontKey *) Tcl_GetHashKey(hPtr->tablePtr, hPtr); - return (char *) keyPtr->string; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_FreeFont -- - * - * Called to release a font allocated by Tk_GetFont(). - * - * Results: - * None. - * - * Side effects: - * The reference count associated with font is decremented, and - * only deallocated when no one is using it. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_FreeFont(tkfont) - Tk_Font tkfont; /* Font to be released. */ -{ - TkFont *fontPtr; - NamedFont *nfPtr; - - if (tkfont == NULL) { - return; - } - fontPtr = (TkFont *) tkfont; - fontPtr->refCount--; - if (fontPtr->refCount == 0) { - if (fontPtr->namedHashPtr != NULL) { - /* - * The font is being deleted. Determine if the associated named - * font definition should and/or can be deleted too. - */ - - nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); - nfPtr->refCount--; - if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { - Tcl_DeleteHashEntry(fontPtr->namedHashPtr); - ckfree((char *) nfPtr); - } - } - Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); - TkpDeleteFont(fontPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_FontId -- - * - * Given a font, return an opaque handle that should be selected - * into the XGCValues structure in order to get the constructed - * gc to use this font. This procedure would go away if the - * XGCValues structure were replaced with a TkGCValues structure. - * - * Results: - * As above. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -Font -Tk_FontId(tkfont) - Tk_Font tkfont; /* Font that is going to be selected into GC. */ -{ - TkFont *fontPtr; - - fontPtr = (TkFont *) tkfont; - return fontPtr->fid; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_GetFontMetrics -- - * - * Returns overall ascent and descent metrics for the given font. - * These values can be used to space multiple lines of text and - * to align the baselines of text in different fonts. - * - * Results: - * If *heightPtr is non-NULL, it is filled with the overall height - * of the font, which is the sum of the ascent and descent. - * If *ascentPtr or *descentPtr is non-NULL, they are filled with - * the ascent and/or descent information for the font. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ -void -Tk_GetFontMetrics(tkfont, fmPtr) - Tk_Font tkfont; /* Font in which metrics are calculated. */ - Tk_FontMetrics *fmPtr; /* Pointer to structure in which font - * metrics for tkfont will be stored. */ -{ - TkFont *fontPtr; - - fontPtr = (TkFont *) tkfont; - fmPtr->ascent = fontPtr->fm.ascent; - fmPtr->descent = fontPtr->fm.descent; - fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_PostscriptFontName -- - * - * Given a Tk_Font, return the name of the corresponding Postscript - * font. - * - * Results: - * The return value is the pointsize of the given Tk_Font. - * The name of the Postscript font is appended to dsPtr. - * - * Side effects: - * If the font does not exist on the printer, the print job will - * fail at print time. Given a "reasonable" Postscript printer, - * the following Tk_Font font families should print correctly: - * - * Avant Garde, Arial, Bookman, Courier, Courier New, Geneva, - * Helvetica, Monaco, New Century Schoolbook, New York, - * Palatino, Symbol, Times, Times New Roman, Zapf Chancery, - * and Zapf Dingbats. - * - * Any other Tk_Font font families may not print correctly - * because the computed Postscript font name may be incorrect. - * - *--------------------------------------------------------------------------- - */ - - -int -Tk_PostscriptFontName(tkfont, dsPtr) - Tk_Font tkfont; /* Font in which text will be printed. */ - Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to - * which the name of the Postscript font that - * corresponds to tkfont will be appended. */ -{ - TkFont *fontPtr; - char *family, *weightString, *slantString; - char *src, *dest; - int upper, len; - - len = Tcl_DStringLength(dsPtr); - fontPtr = (TkFont *) tkfont; - - /* - * Convert the case-insensitive Tk_Font family name to the - * case-sensitive Postscript family name. Take out any spaces and - * capitalize the first letter of each word. - */ - - family = fontPtr->fa.family; - if (strncasecmp(family, "itc ", 4) == 0) { - family = family + 4; - } - if ((strcasecmp(family, "Arial") == 0) - || (strcasecmp(family, "Geneva") == 0)) { - family = "Helvetica"; - } else if ((strcasecmp(family, "Times New Roman") == 0) - || (strcasecmp(family, "New York") == 0)) { - family = "Times"; - } else if ((strcasecmp(family, "Courier New") == 0) - || (strcasecmp(family, "Monaco") == 0)) { - family = "Courier"; - } else if (strcasecmp(family, "AvantGarde") == 0) { - family = "AvantGarde"; - } else if (strcasecmp(family, "ZapfChancery") == 0) { - family = "ZapfChancery"; - } else if (strcasecmp(family, "ZapfDingbats") == 0) { - family = "ZapfDingbats"; - } else { - /* - * Inline, capitalize the first letter of each word, lowercase the - * rest of the letters in each word, and then take out the spaces - * between the words. This may make the DString shorter, which is - * safe to do. - */ - - Tcl_DStringAppend(dsPtr, family, -1); - - src = dest = Tcl_DStringValue(dsPtr) + len; - upper = 1; - for (; *src != '\0'; src++, dest++) { - while (isspace(UCHAR(*src))) { - src++; - upper = 1; - } - *dest = *src; - if ((upper != 0) && (islower(UCHAR(*src)))) { - *dest = toupper(UCHAR(*src)); - } - upper = 0; - } - *dest = '\0'; - Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr)); - family = Tcl_DStringValue(dsPtr) + len; - } - if (family != Tcl_DStringValue(dsPtr) + len) { - Tcl_DStringAppend(dsPtr, family, -1); - family = Tcl_DStringValue(dsPtr) + len; - } - - if (strcasecmp(family, "NewCenturySchoolbook") == 0) { - Tcl_DStringSetLength(dsPtr, len); - Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1); - family = Tcl_DStringValue(dsPtr) + len; - } - - /* - * Get the string to use for the weight. - */ - - weightString = NULL; - if (fontPtr->fa.weight == TK_FW_NORMAL) { - if (strcmp(family, "Bookman") == 0) { - weightString = "Light"; - } else if (strcmp(family, "AvantGarde") == 0) { - weightString = "Book"; - } else if (strcmp(family, "ZapfChancery") == 0) { - weightString = "Medium"; - } - } else { - if ((strcmp(family, "Bookman") == 0) - || (strcmp(family, "AvantGarde") == 0)) { - weightString = "Demi"; - } else { - weightString = "Bold"; - } - } - - /* - * Get the string to use for the slant. - */ - - slantString = NULL; - if (fontPtr->fa.slant == TK_FS_ROMAN) { - ; - } else { - if ((strcmp(family, "Helvetica") == 0) - || (strcmp(family, "Courier") == 0) - || (strcmp(family, "AvantGarde") == 0)) { - slantString = "Oblique"; - } else { - slantString = "Italic"; - } - } - - /* - * The string "Roman" needs to be added to some fonts that are not bold - * and not italic. - */ - - if ((slantString == NULL) && (weightString == NULL)) { - if ((strcmp(family, "Times") == 0) - || (strcmp(family, "NewCenturySchlbk") == 0) - || (strcmp(family, "Palatino") == 0)) { - Tcl_DStringAppend(dsPtr, "-Roman", -1); - } - } else { - Tcl_DStringAppend(dsPtr, "-", -1); - if (weightString != NULL) { - Tcl_DStringAppend(dsPtr, weightString, -1); - } - if (slantString != NULL) { - Tcl_DStringAppend(dsPtr, slantString, -1); - } - } - - return fontPtr->fa.pointsize; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_TextWidth -- - * - * A wrapper function for the more complicated interface of - * Tk_MeasureChars. Computes how much space the given - * simple string needs. - * - * Results: - * The return value is the width (in pixels) of the given string. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tk_TextWidth(tkfont, string, numChars) - Tk_Font tkfont; /* Font in which text will be measured. */ - CONST char *string; /* String whose width will be computed. */ - int numChars; /* Number of characters to consider from - * string, or < 0 for strlen(). */ -{ - int width; - - if (numChars < 0) { - numChars = strlen(string); - } - Tk_MeasureChars(tkfont, string, numChars, 0, 0, &width); - return width; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_UnderlineChars -- - * - * This procedure draws an underline for a given range of characters - * in a given string. It doesn't draw the characters (which are - * assumed to have been displayed previously); it just draws the - * underline. This procedure would mainly be used to quickly - * underline a few characters without having to construct an - * underlined font. To produce properly underlined text, the - * appropriate underlined font should be constructed and used. - * - * Results: - * None. - * - * Side effects: - * Information gets displayed in "drawable". - * - *---------------------------------------------------------------------- - */ - -void -Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar, - lastChar) - Display *display; /* Display on which to draw. */ - Drawable drawable; /* Window or pixmap in which to draw. */ - GC gc; /* Graphics context for actually drawing - * line. */ - Tk_Font tkfont; /* Font used in GC; must have been allocated - * by Tk_GetFont(). Used for character - * dimensions, etc. */ - CONST char *string; /* String containing characters to be - * underlined or overstruck. */ - int x, y; /* Coordinates at which first character of - * string is drawn. */ - int firstChar; /* Index of first character. */ - int lastChar; /* Index of one after the last character. */ -{ - TkFont *fontPtr; - int startX, endX; - - fontPtr = (TkFont *) tkfont; - - Tk_MeasureChars(tkfont, string, firstChar, 0, 0, &startX); - Tk_MeasureChars(tkfont, string, lastChar, 0, 0, &endX); - - XFillRectangle(display, drawable, gc, x + startX, - y + fontPtr->underlinePos, (unsigned int) (endX - startX), - (unsigned int) fontPtr->underlineHeight); -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_ComputeTextLayout -- - * - * Computes the amount of screen space needed to display a - * multi-line, justified string of text. Records all the - * measurements that were done to determine to size and - * positioning of the individual lines of text; this information - * can be used by the Tk_DrawTextLayout() procedure to - * display the text quickly (without remeasuring it). - * - * This procedure is useful for simple widgets that want to - * display single-font, multi-line text and want Tk to handle the - * details. - * - * Results: - * The return value is a Tk_TextLayout token that holds the - * measurement information for the given string. The token is - * only valid for the given string. If the string is freed, - * the token is no longer valid and must also be freed. To free - * the token, call Tk_FreeTextLayout(). - * - * The dimensions of the screen area needed to display the text - * are stored in *widthPtr and *heightPtr. - * - * Side effects: - * Memory is allocated to hold the measurement information. - * - *--------------------------------------------------------------------------- - */ - -Tk_TextLayout -Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, - widthPtr, heightPtr) - Tk_Font tkfont; /* Font that will be used to display text. */ - CONST char *string; /* String whose dimensions are to be - * computed. */ - int numChars; /* Number of characters to consider from - * string, or < 0 for strlen(). */ - int wrapLength; /* Longest permissible line length, in - * pixels. <= 0 means no automatic wrapping: - * just let lines get as long as needed. */ - Tk_Justify justify; /* How to justify lines. */ - int flags; /* Flag bits OR-ed together. - * TK_IGNORE_TABS means that tab characters - * should not be expanded. TK_IGNORE_NEWLINES - * means that newline characters should not - * cause a line break. */ - int *widthPtr; /* Filled with width of string. */ - int *heightPtr; /* Filled with height of string. */ -{ - TkFont *fontPtr; - CONST char *start, *end, *special; - int n, y, charsThisChunk, maxChunks; - int baseline, height, curX, newX, maxWidth; - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - CONST TkFontMetrics *fmPtr; -#define MAX_LINES 50 - int staticLineLengths[MAX_LINES]; - int *lineLengths; - int maxLines, curLine, layoutHeight; - - lineLengths = staticLineLengths; - maxLines = MAX_LINES; - - fontPtr = (TkFont *) tkfont; - fmPtr = &fontPtr->fm; - - height = fmPtr->ascent + fmPtr->descent; - - if (numChars < 0) { - numChars = strlen(string); - } - - maxChunks = 1; - - layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout) - + (maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr->tkfont = tkfont; - layoutPtr->string = string; - layoutPtr->numChunks = 0; - - baseline = fmPtr->ascent; - maxWidth = 0; - - /* - * Divide the string up into simple strings and measure each string. - */ - - curX = 0; - - end = string + numChars; - special = string; - - flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES; - flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE; - curLine = 0; - for (start = string; start < end; ) { - if (start >= special) { - /* - * Find the next special character in the string. - */ - - for (special = start; special < end; special++) { - if (!(flags & TK_IGNORE_NEWLINES)) { - if ((*special == '\n') || (*special == '\r')) { - break; - } - } - if (!(flags & TK_IGNORE_TABS)) { - if (*special == '\t') { - break; - } - } - } - } - - /* - * Special points at the next special character (or the end of the - * string). Process characters between start and special. - */ - - chunkPtr = NULL; - if (start < special) { - charsThisChunk = Tk_MeasureChars(tkfont, start, special - start, - wrapLength - curX, flags, &newX); - newX += curX; - flags &= ~TK_AT_LEAST_ONE; - if (charsThisChunk > 0) { - chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, - charsThisChunk, curX, newX, baseline); - - start += charsThisChunk; - curX = newX; - } - } - - if ((start == special) && (special < end)) { - /* - * Handle the special character. - */ - - chunkPtr = NULL; - if (*special == '\t') { - newX = curX + fontPtr->tabWidth; - newX -= newX % fontPtr->tabWidth; - NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX, - baseline)->numDisplayChars = -1; - start++; - if ((start < end) && - ((wrapLength <= 0) || (newX <= wrapLength))) { - /* - * More chars can still fit on this line. - */ - - curX = newX; - flags &= ~TK_AT_LEAST_ONE; - continue; - } - } else { - NewChunk(&layoutPtr, &maxChunks, start, 1, curX, 1000000000, - baseline)->numDisplayChars = -1; - start++; - goto wrapLine; - } - } - - /* - * No more characters are going to go on this line, either because - * no more characters can fit or there are no more characters left. - * Consume all extra spaces at end of line. - */ - - while ((start < end) && isspace(UCHAR(*start))) { - if (!(flags & TK_IGNORE_NEWLINES)) { - if ((*start == '\n') || (*start == '\r')) { - break; - } - } - if (!(flags & TK_IGNORE_TABS)) { - if (*start == '\t') { - break; - } - } - start++; - } - if (chunkPtr != NULL) { - /* - * Append all the extra spaces on this line to the end of the - * last text chunk. - */ - charsThisChunk = start - (chunkPtr->start + chunkPtr->numChars); - if (charsThisChunk > 0) { - chunkPtr->numChars += Tk_MeasureChars(tkfont, - chunkPtr->start + chunkPtr->numChars, charsThisChunk, - 0, 0, &chunkPtr->totalWidth); - chunkPtr->totalWidth += curX; - } - } - - wrapLine: - flags |= TK_AT_LEAST_ONE; - - /* - * Save current line length, then move current position to start of - * next line. - */ - - if (curX > maxWidth) { - maxWidth = curX; - } - - /* - * Remember width of this line, so that all chunks on this line - * can be centered or right justified, if necessary. - */ - - if (curLine >= maxLines) { - int *newLengths; - - newLengths = (int *) ckalloc(2 * maxLines * sizeof(int)); - memcpy((void *) newLengths, lineLengths, maxLines * sizeof(int)); - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } - lineLengths = newLengths; - maxLines *= 2; - } - lineLengths[curLine] = curX; - curLine++; - - curX = 0; - baseline += height; - } - - /* - * If last line ends with a newline, then we need to make a 0 width - * chunk on the next line. Otherwise "Hello" and "Hello\n" are the - * same height. - */ - - if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) { - if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') { - chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX, - 1000000000, baseline); - chunkPtr->numDisplayChars = -1; - baseline += height; - } - } - - /* - * Using maximum line length, shift all the chunks so that the lines are - * all justified correctly. - */ - - curLine = 0; - chunkPtr = layoutPtr->chunks; - y = chunkPtr->y; - for (n = 0; n < layoutPtr->numChunks; n++) { - int extra; - - if (chunkPtr->y != y) { - curLine++; - y = chunkPtr->y; - } - extra = maxWidth - lineLengths[curLine]; - if (justify == TK_JUSTIFY_CENTER) { - chunkPtr->x += extra / 2; - } else if (justify == TK_JUSTIFY_RIGHT) { - chunkPtr->x += extra; - } - chunkPtr++; - } - - layoutPtr->width = maxWidth; - layoutHeight = baseline - fmPtr->ascent; - if (layoutPtr->numChunks == 0) { - layoutHeight = height; - - /* - * This fake chunk is used by the other procedures so that they can - * pretend that there is a chunk with no chars in it, which makes - * the coding simpler. - */ - - layoutPtr->numChunks = 1; - layoutPtr->chunks[0].start = string; - layoutPtr->chunks[0].numChars = 0; - layoutPtr->chunks[0].numDisplayChars = -1; - layoutPtr->chunks[0].x = 0; - layoutPtr->chunks[0].y = fmPtr->ascent; - layoutPtr->chunks[0].totalWidth = 0; - layoutPtr->chunks[0].displayWidth = 0; - } - - if (widthPtr != NULL) { - *widthPtr = layoutPtr->width; - } - if (heightPtr != NULL) { - *heightPtr = layoutHeight; - } - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } - - return (Tk_TextLayout) layoutPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_FreeTextLayout -- - * - * This procedure is called to release the storage associated with - * a Tk_TextLayout when it is no longer needed. - * - * Results: - * None. - * - * Side effects: - * Memory is freed. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_FreeTextLayout(textLayout) - Tk_TextLayout textLayout; /* The text layout to be released. */ -{ - TextLayout *layoutPtr; - - layoutPtr = (TextLayout *) textLayout; - if (layoutPtr != NULL) { - ckfree((char *) layoutPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_DrawTextLayout -- - * - * Use the information in the Tk_TextLayout token to display a - * multi-line, justified string of text. - * - * This procedure is useful for simple widgets that need to - * display single-font, multi-line text and want Tk to handle - * the details. - * - * Results: - * None. - * - * Side effects: - * Text drawn on the screen. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) - Display *display; /* Display on which to draw. */ - Drawable drawable; /* Window or pixmap in which to draw. */ - GC gc; /* Graphics context to use for drawing text. */ - Tk_TextLayout layout; /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, y; /* Upper-left hand corner of rectangle in - * which to draw (pixels). */ - int firstChar; /* The index of the first character to draw - * from the given text item. 0 specfies the - * beginning. */ - int lastChar; /* The index just after the last character - * to draw from the given text item. A number - * < 0 means to draw all characters. */ -{ - TextLayout *layoutPtr; - int i, numDisplayChars, drawX; - LayoutChunk *chunkPtr; - - layoutPtr = (TextLayout *) layout; - if (layoutPtr == NULL) { - return; - } - - if (lastChar < 0) { - lastChar = 100000000; - } - chunkPtr = layoutPtr->chunks; - for (i = 0; i < layoutPtr->numChunks; i++) { - numDisplayChars = chunkPtr->numDisplayChars; - if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) { - if (firstChar <= 0) { - drawX = 0; - firstChar = 0; - } else { - Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, firstChar, - 0, 0, &drawX); - } - if (lastChar < numDisplayChars) { - numDisplayChars = lastChar; - } - Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, - chunkPtr->start + firstChar, numDisplayChars - firstChar, - x + chunkPtr->x + drawX, y + chunkPtr->y); - } - firstChar -= chunkPtr->numChars; - lastChar -= chunkPtr->numChars; - if (lastChar <= 0) { - break; - } - chunkPtr++; - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_UnderlineTextLayout -- - * - * Use the information in the Tk_TextLayout token to display an - * underline below an individual character. This procedure does - * not draw the text, just the underline. - * - * This procedure is useful for simple widgets that need to - * display single-font, multi-line text with an individual - * character underlined and want Tk to handle the details. - * To display larger amounts of underlined text, construct - * and use an underlined font. - * - * Results: - * None. - * - * Side effects: - * Underline drawn on the screen. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline) - Display *display; /* Display on which to draw. */ - Drawable drawable; /* Window or pixmap in which to draw. */ - GC gc; /* Graphics context to use for drawing text. */ - Tk_TextLayout layout; /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, y; /* Upper-left hand corner of rectangle in - * which to draw (pixels). */ - int underline; /* Index of the single character to - * underline, or -1 for no underline. */ -{ - TextLayout *layoutPtr; - TkFont *fontPtr; - int xx, yy, width, height; - - if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) - && (width != 0)) { - layoutPtr = (TextLayout *) layout; - fontPtr = (TkFont *) layoutPtr->tkfont; - - XFillRectangle(display, drawable, gc, x + xx, - y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, - (unsigned int) width, (unsigned int) fontPtr->underlineHeight); - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_PointToChar -- - * - * Use the information in the Tk_TextLayout token to determine the - * character closest to the given point. The point must be - * specified with respect to the upper-left hand corner of the - * text layout, which is considered to be located at (0, 0). - * - * Any point whose y-value is less that 0 will be considered closest - * to the first character in the text layout; any point whose y-value - * is greater than the height of the text layout will be considered - * closest to the last character in the text layout. - * - * Any point whose x-value is less than 0 will be considered closest - * to the first character on that line; any point whose x-value is - * greater than the width of the text layout will be considered - * closest to the last character on that line. - * - * Results: - * The return value is the index of the character that was - * closest to the point. Given a text layout with no characters, - * the value 0 will always be returned, referring to a hypothetical - * zero-width placeholder character. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tk_PointToChar(layout, x, y) - Tk_TextLayout layout; /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, y; /* Coordinates of point to check, with - * respect to the upper-left corner of the - * text layout. */ -{ - TextLayout *layoutPtr; - LayoutChunk *chunkPtr, *lastPtr; - TkFont *fontPtr; - int i, n, dummy, baseline, pos; - - if (y < 0) { - /* - * Point lies above any line in this layout. Return the index of - * the first char. - */ - - return 0; - } - - /* - * Find which line contains the point. - */ - - layoutPtr = (TextLayout *) layout; - fontPtr = (TkFont *) layoutPtr->tkfont; - lastPtr = chunkPtr = layoutPtr->chunks; - for (i = 0; i < layoutPtr->numChunks; i++) { - baseline = chunkPtr->y; - if (y < baseline + fontPtr->fm.descent) { - if (x < chunkPtr->x) { - /* - * Point is to the left of all chunks on this line. Return - * the index of the first character on this line. - */ - - return chunkPtr->start - layoutPtr->string; - } - if (x >= layoutPtr->width) { - /* - * If point lies off right side of the text layout, return - * the last char in the last chunk on this line. Without - * this, it might return the index of the first char that - * was located outside of the text layout. - */ - - x = INT_MAX; - } - - /* - * Examine all chunks on this line to see which one contains - * the specified point. - */ - - lastPtr = chunkPtr; - while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline)) { - if (x < chunkPtr->x + chunkPtr->totalWidth) { - /* - * Point falls on one of the characters in this chunk. - */ - - if (chunkPtr->numDisplayChars < 0) { - /* - * This is a special chunk that encapsulates a single - * tab or newline char. - */ - - return chunkPtr->start - layoutPtr->string; - } - n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start, - chunkPtr->numChars, x + 1 - chunkPtr->x, - TK_PARTIAL_OK, &dummy); - return (chunkPtr->start + n - 1) - layoutPtr->string; - } - lastPtr = chunkPtr; - chunkPtr++; - i++; - } - - /* - * Point is to the right of all chars in all the chunks on this - * line. Return the index just past the last char in the last - * chunk on this line. - */ - - pos = (lastPtr->start + lastPtr->numChars) - layoutPtr->string; - if (i < layoutPtr->numChunks) { - pos--; - } - return pos; - } - lastPtr = chunkPtr; - chunkPtr++; - } - - /* - * Point lies below any line in this text layout. Return the index - * just past the last char. - */ - - return (lastPtr->start + lastPtr->numChars) - layoutPtr->string; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_CharBbox -- - * - * Use the information in the Tk_TextLayout token to return the - * bounding box for the character specified by index. - * - * The width of the bounding box is the advance width of the - * character, and does not include and left- or right-bearing. - * Any character that extends partially outside of the - * text layout is considered to be truncated at the edge. Any - * character which is located completely outside of the text - * layout is considered to be zero-width and pegged against - * the edge. - * - * The height of the bounding box is the line height for this font, - * extending from the top of the ascent to the bottom of the - * descent. Information about the actual height of the individual - * letter is not available. - * - * A text layout that contains no characters is considered to - * contain a single zero-width placeholder character. - * - * Results: - * The return value is 0 if the index did not specify a character - * in the text layout, or non-zero otherwise. In that case, - * *bbox is filled with the bounding box of the character. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) - Tk_TextLayout layout; /* Layout information, from a previous call to - * Tk_ComputeTextLayout(). */ - int index; /* The index of the character whose bbox is - * desired. */ - int *xPtr, *yPtr; /* Filled with the upper-left hand corner, in - * pixels, of the bounding box for the character - * specified by index, if non-NULL. */ - int *widthPtr, *heightPtr; - /* Filled with the width and height of the - * bounding box for the character specified by - * index, if non-NULL. */ -{ - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - int i, x, w; - Tk_Font tkfont; - TkFont *fontPtr; - - if (index < 0) { - return 0; - } - - layoutPtr = (TextLayout *) layout; - chunkPtr = layoutPtr->chunks; - tkfont = layoutPtr->tkfont; - fontPtr = (TkFont *) tkfont; - - for (i = 0; i < layoutPtr->numChunks; i++) { - if (chunkPtr->numDisplayChars < 0) { - if (index == 0) { - x = chunkPtr->x; - w = chunkPtr->totalWidth; - goto check; - } - } else if (index < chunkPtr->numChars) { - if (xPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start, index, 0, 0, &x); - x += chunkPtr->x; - } - if (widthPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start + index, 1, 0, 0, &w); - } - goto check; - } - index -= chunkPtr->numChars; - chunkPtr++; - } - if (index == 0) { - /* - * Special case to get location just past last char in layout. - */ - - chunkPtr--; - x = chunkPtr->x + chunkPtr->totalWidth; - w = 0; - } else { - return 0; - } - - /* - * Ensure that the bbox lies within the text layout. This forces all - * chars that extend off the right edge of the text layout to have - * truncated widths, and all chars that are completely off the right - * edge of the text layout to peg to the edge and have 0 width. - */ - check: - if (yPtr != NULL) { - *yPtr = chunkPtr->y - fontPtr->fm.ascent; - } - if (heightPtr != NULL) { - *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent; - } - - if (x > layoutPtr->width) { - x = layoutPtr->width; - } - if (xPtr != NULL) { - *xPtr = x; - } - if (widthPtr != NULL) { - if (x + w > layoutPtr->width) { - w = layoutPtr->width - x; - } - *widthPtr = w; - } - - return 1; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_DistanceToTextLayout -- - * - * Computes the distance in pixels from the given point to the - * given text layout. Non-displaying space characters that occur - * at the end of individual lines in the text layout are ignored - * for hit detection purposes. - * - * Results: - * The return value is 0 if the point (x, y) is inside the text - * layout. If the point isn't inside the text layout then the - * return value is the distance in pixels from the point to the - * text item. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tk_DistanceToTextLayout(layout, x, y) - Tk_TextLayout layout; /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, y; /* Coordinates of point to check, with - * respect to the upper-left corner of the - * text layout (in pixels). */ -{ - int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent; - LayoutChunk *chunkPtr; - TextLayout *layoutPtr; - TkFont *fontPtr; - - layoutPtr = (TextLayout *) layout; - fontPtr = (TkFont *) layoutPtr->tkfont; - ascent = fontPtr->fm.ascent; - descent = fontPtr->fm.descent; - - minDist = 0; - chunkPtr = layoutPtr->chunks; - for (i = 0; i < layoutPtr->numChunks; i++) { - if (chunkPtr->start[0] == '\n') { - /* - * Newline characters are not counted when computing distance - * (but tab characters would still be considered). - */ - - chunkPtr++; - continue; - } - - x1 = chunkPtr->x; - y1 = chunkPtr->y - ascent; - x2 = chunkPtr->x + chunkPtr->displayWidth; - y2 = chunkPtr->y + descent; - - if (x < x1) { - xDiff = x1 - x; - } else if (x >= x2) { - xDiff = x - x2 + 1; - } else { - xDiff = 0; - } - - if (y < y1) { - yDiff = y1 - y; - } else if (y >= y2) { - yDiff = y - y2 + 1; - } else { - yDiff = 0; - } - if ((xDiff == 0) && (yDiff == 0)) { - return 0; - } - dist = (int) hypot((double) xDiff, (double) yDiff); - if ((dist < minDist) || (minDist == 0)) { - minDist = dist; - } - chunkPtr++; - } - return minDist; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_IntersectTextLayout -- - * - * Determines whether a text layout lies entirely inside, - * entirely outside, or overlaps a given rectangle. Non-displaying - * space characters that occur at the end of individual lines in - * the text layout are ignored for intersection calculations. - * - * Results: - * The return value is -1 if the text layout is entirely outside of - * the rectangle, 0 if it overlaps, and 1 if it is entirely inside - * of the rectangle. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tk_IntersectTextLayout(layout, x, y, width, height) - Tk_TextLayout layout; /* Layout information, from a previous call - * to Tk_ComputeTextLayout(). */ - int x, y; /* Upper-left hand corner, in pixels, of - * rectangular area to compare with text - * layout. Coordinates are with respect to - * the upper-left hand corner of the text - * layout itself. */ - int width, height; /* The width and height of the above - * rectangular area, in pixels. */ -{ - int result, i, x1, y1, x2, y2; - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - TkFont *fontPtr; - int left, top, right, bottom; - - /* - * Scan the chunks one at a time, seeing whether each is entirely in, - * entirely out, or overlapping the rectangle. If an overlap is - * detected, return immediately; otherwise wait until all chunks have - * been processed and see if they were all inside or all outside. - */ - - layoutPtr = (TextLayout *) layout; - chunkPtr = layoutPtr->chunks; - fontPtr = (TkFont *) layoutPtr->tkfont; - - left = x; - top = y; - right = x + width; - bottom = y + height; - - result = 0; - for (i = 0; i < layoutPtr->numChunks; i++) { - if (chunkPtr->start[0] == '\n') { - /* - * Newline characters are not counted when computing area - * intersection (but tab characters would still be considered). - */ - - chunkPtr++; - continue; - } - - x1 = chunkPtr->x; - y1 = chunkPtr->y - fontPtr->fm.ascent; - x2 = chunkPtr->x + chunkPtr->displayWidth; - y2 = chunkPtr->y + fontPtr->fm.descent; - - if ((right < x1) || (left >= x2) - || (bottom < y1) || (top >= y2)) { - if (result == 1) { - return 0; - } - result = -1; - } else if ((x1 < left) || (x2 >= right) - || (y1 < top) || (y2 >= bottom)) { - return 0; - } else if (result == -1) { - return 0; - } else { - result = 1; - } - chunkPtr++; - } - return result; -} - -/* - *--------------------------------------------------------------------------- - * - * Tk_TextLayoutToPostscript -- - * - * Outputs the contents of a text layout in Postscript format. - * The set of lines in the text layout will be rendered by the user - * supplied Postscript function. The function should be of the form: - * - * justify x y string function -- - * - * Justify is -1, 0, or 1, depending on whether the following string - * should be left, center, or right justified, x and y is the - * location for the origin of the string, string is the sequence - * of characters to be printed, and function is the name of the - * caller-provided function; the function should leave nothing - * on the stack. - * - * The meaning of the origin of the string (x and y) depends on - * the justification. For left justification, x is where the - * left edge of the string should appear. For center justification, - * x is where the center of the string should appear. And for right - * justification, x is where the right edge of the string should - * appear. This behavior is necessary because, for example, right - * justified text on the screen is justified with screen metrics. - * The same string needs to be justified with printer metrics on - * the printer to appear in the correct place with respect to other - * similarly justified strings. In all circumstances, y is the - * location of the baseline for the string. - * - * Results: - * Interp->result is modified to hold the Postscript code that - * will render the text layout. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -void -Tk_TextLayoutToPostscript(interp, layout) - Tcl_Interp *interp; /* Filled with Postscript code. */ - Tk_TextLayout layout; /* The layout to be rendered. */ -{ -#define MAXUSE 128 - char buf[MAXUSE+10]; - LayoutChunk *chunkPtr; - int i, j, used, c, baseline; - TextLayout *layoutPtr; - - layoutPtr = (TextLayout *) layout; - chunkPtr = layoutPtr->chunks; - baseline = chunkPtr->y; - used = 0; - buf[used++] = '('; - for (i = 0; i < layoutPtr->numChunks; i++) { - if (baseline != chunkPtr->y) { - buf[used++] = ')'; - buf[used++] = '\n'; - buf[used++] = '('; - baseline = chunkPtr->y; - } - if (chunkPtr->numDisplayChars <= 0) { - if (chunkPtr->start[0] == '\t') { - buf[used++] = '\\'; - buf[used++] = 't'; - } - } else { - for (j = 0; j < chunkPtr->numDisplayChars; j++) { - c = UCHAR(chunkPtr->start[j]); - if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) - || (c >= UCHAR(0x7f))) { - /* - * Tricky point: the "03" is necessary in the sprintf - * below, so that a full three digits of octal are - * always generated. Without the "03", a number - * following this sequence could be interpreted by - * Postscript as part of this sequence. - */ - - sprintf(buf + used, "\\%03o", c); - used += 4; - } else { - buf[used++] = c; - } - if (used >= MAXUSE) { - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, (char *) NULL); - used = 0; - } - } - } - if (used >= MAXUSE) { - /* - * If there are a whole bunch of returns or tabs in a row, - * then buf[] could get filled up. - */ - - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, (char *) NULL); - used = 0; - } - chunkPtr++; - } - buf[used++] = ')'; - buf[used++] = '\n'; - buf[used] = '\0'; - Tcl_AppendResult(interp, buf, (char *) NULL); -} - -/* - *--------------------------------------------------------------------------- - * - * TkInitFontAttributes -- - * - * Initialize the font attributes structure to contain sensible - * values. This must be called before using any other font - * attributes functions. - * - * Results: - * None. - * - * Side effects. - * None. - * - *--------------------------------------------------------------------------- - */ - -void -TkInitFontAttributes(faPtr) - TkFontAttributes *faPtr; /* The attributes structure to initialize. */ -{ - faPtr->family = NULL; - faPtr->pointsize = 0; - faPtr->weight = TK_FW_NORMAL; - faPtr->slant = TK_FS_ROMAN; - faPtr->underline = 0; - faPtr->overstrike = 0; -} - -/* - *--------------------------------------------------------------------------- - * - * ConfigAttributesObj -- - * - * Process command line options to fill in fields of a properly - * initialized font attributes structure. - * - * Results: - * A standard Tcl return value. If TCL_ERROR is returned, an - * error message will be left in interp's result object. - * - * Side effects: - * The fields of the font attributes structure get filled in with - * information from argc/argv. If an error occurs while parsing, - * the font attributes structure will contain all modifications - * specified in the command line options up to the point of the - * error. - * - *--------------------------------------------------------------------------- - */ - -static int -ConfigAttributesObj(interp, tkwin, objc, objv, faPtr) - Tcl_Interp *interp; /* Interp for error return. */ - Tk_Window tkwin; /* For display on which font will be used. */ - int objc; /* Number of elements in argv. */ - Tcl_Obj *CONST objv[]; /* Command line options. */ - TkFontAttributes *faPtr; /* Font attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ -{ - int i, n, index; - Tcl_Obj *value; - char *option, *string; - - if (objc & 1) { - string = Tcl_GetStringFromObj(objv[objc - 1], NULL); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "missing value for \"", - string, "\" option", (char *) NULL); - return TCL_ERROR; - } - - for (i = 0; i < objc; i += 2) { - option = Tcl_GetStringFromObj(objv[i], NULL); - value = objv[i + 1]; - - if (Tcl_GetIndexFromObj(interp, objv[i], fontOpt, "option", 1, - &index) != TCL_OK) { - return TCL_ERROR; - } - switch (index) { - case FONT_FAMILY: - string = Tcl_GetStringFromObj(value, NULL); - faPtr->family = Tk_GetUid(string); - break; - - case FONT_SIZE: - if (Tcl_GetIntFromObj(interp, value, &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->pointsize = n; - break; - - case FONT_WEIGHT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, weightMap, string); - if (n == TK_FW_UNKNOWN) { - return TCL_ERROR; - } - faPtr->weight = n; - break; - - case FONT_SLANT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, slantMap, string); - if (n == TK_FS_UNKNOWN) { - return TCL_ERROR; - } - faPtr->slant = n; - break; - - case FONT_UNDERLINE: - if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->underline = n; - break; - - case FONT_OVERSTRIKE: - if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->overstrike = n; - break; - } - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * GetAttributeInfoObj -- - * - * Return information about the font attributes as a Tcl list. - * - * Results: - * The return value is TCL_OK if the objPtr was non-NULL and - * specified a valid font attribute, TCL_ERROR otherwise. If TCL_OK - * is returned, the interp's result object is modified to hold a - * description of either the current value of a single option, or a - * list of all options and their current values for the given font - * attributes. If TCL_ERROR is returned, the interp's result is - * set to an error message describing that the objPtr did not refer - * to a valid option. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -GetAttributeInfoObj(interp, faPtr, objPtr) - Tcl_Interp *interp; /* Interp to hold result. */ - CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */ - Tcl_Obj *objPtr; /* If non-NULL, indicates the single - * option whose value is to be - * returned. Otherwise - * information is returned for - * all options. */ -{ - int i, index, start, end, num; - char *str; - Tcl_Obj *newPtr; - - start = 0; - end = FONT_NUMFIELDS; - if (objPtr != NULL) { - if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", 1, - &index) != TCL_OK) { - return TCL_ERROR; - } - start = index; - end = index + 1; - } - - for (i = start; i < end; i++) { - str = NULL; - num = 0; /* Needed only to prevent compiler - * warning. */ - switch (i) { - case FONT_FAMILY: - str = faPtr->family; - if (str == NULL) { - str = ""; - } - break; - - case FONT_SIZE: - num = faPtr->pointsize; - break; - - case FONT_WEIGHT: - str = TkFindStateString(weightMap, faPtr->weight); - break; - - case FONT_SLANT: - str = TkFindStateString(slantMap, faPtr->slant); - break; - - case FONT_UNDERLINE: - num = faPtr->underline; - break; - - case FONT_OVERSTRIKE: - num = faPtr->overstrike; - break; - } - if (objPtr == NULL) { - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - Tcl_NewStringObj(fontOpt[i], -1)); - if (str != NULL) { - newPtr = Tcl_NewStringObj(str, -1); - } else { - newPtr = Tcl_NewIntObj(num); - } - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - newPtr); - } else { - if (str != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), str, -1); - } else { - Tcl_SetIntObj(Tcl_GetObjResult(interp), num); - } - } - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ParseFontNameObj -- - * - * Converts a object into a set of font attributes that can be used - * to construct a font. - * - * The string rep of the object can be one of the following forms: - * XLFD (see X documentation) - * "Family [size [style] [style ...]]" - * "-option value [-option value ...]" - * - * Results: - * The return value is TCL_ERROR if the object was syntactically - * invalid. In that case an error message is left in interp's - * result object. Otherwise, fills the font attribute buffer with - * the values parsed from the string and returns TCL_OK; - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -ParseFontNameObj(interp, tkwin, objPtr, faPtr) - Tcl_Interp *interp; /* Interp for error return. */ - Tk_Window tkwin; /* For display on which font is used. */ - Tcl_Obj *objPtr; /* Parseable font description object. */ - TkFontAttributes *faPtr; /* Font attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ -{ - char *dash; - int objc, result, i, n; - Tcl_Obj **objv; - TkXLFDAttributes xa; - char *string; - - string = Tcl_GetStringFromObj(objPtr, NULL); - if (*string == '-') { - /* - * This may be an XLFD or an "-option value" string. - * - * If the string begins with "-*" or a "-foundry-family-*" pattern, - * then consider it an XLFD. - */ - - if (string[1] == '*') { - goto xlfd; - } - dash = strchr(string + 1, '-'); - if ((dash != NULL) && (!isspace(UCHAR(dash[-1])))) { - goto xlfd; - } - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - - return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr); - } - - if (*string == '*') { - /* - * This appears to be an XLFD. - */ - - xlfd: - xa.fa = *faPtr; - result = TkParseXLFD(string, &xa); - if (result == TCL_OK) { - *faPtr = xa.fa; - return result; - } - } - - /* - * Wasn't an XLFD or "-option value" string. Try it as a - * "font size style" list. - */ - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - if (objc < 1) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "font \"", string, - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - - faPtr->family = Tk_GetUid(Tcl_GetStringFromObj(objv[0], NULL)); - if (objc > 1) { - if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) { - return TCL_ERROR; - } - faPtr->pointsize = n; - } - - i = 2; - if (objc == 3) { - if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - i = 0; - } - for ( ; i < objc; i++) { - string = Tcl_GetStringFromObj(objv[i], NULL); - n = TkFindStateNum(NULL, NULL, weightMap, string); - if (n != TK_FW_UNKNOWN) { - faPtr->weight = n; - continue; - } - n = TkFindStateNum(NULL, NULL, slantMap, string); - if (n != TK_FS_UNKNOWN) { - faPtr->slant = n; - continue; - } - n = TkFindStateNum(NULL, NULL, underlineMap, string); - if (n != 0) { - faPtr->underline = n; - continue; - } - n = TkFindStateNum(NULL, NULL, overstrikeMap, string); - if (n != 0) { - faPtr->overstrike = n; - continue; - } - - /* - * Unknown style. - */ - - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "unknown font style \"", string, "\"", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * TkParseXLFD -- - * - * Break up a fully specified XLFD into a set of font attributes. - * - * Results: - * Return value is TCL_ERROR if string was not a fully specified XLFD. - * Otherwise, fills font attribute buffer with the values parsed - * from the XLFD and returns TCL_OK. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -TkParseXLFD(string, xaPtr) - CONST char *string; /* Parseable font description string. */ - TkXLFDAttributes *xaPtr; /* XLFD attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ -{ - char *src; - CONST char *str; - int i, j; - char *field[XLFD_NUMFIELDS + 2]; - Tcl_DString ds; - - memset(field, '\0', sizeof(field)); - - str = string; - if (*str == '-') { - str++; - } - - Tcl_DStringInit(&ds); - Tcl_DStringAppend(&ds, (char *) str, -1); - src = Tcl_DStringValue(&ds); - - field[0] = src; - for (i = 0; *src != '\0'; src++) { - if (isupper(UCHAR(*src))) { - *src = tolower(UCHAR(*src)); - } - if (*src == '-') { - i++; - if (i > XLFD_NUMFIELDS) { - break; - } - *src = '\0'; - field[i] = src + 1; - } - } - - /* - * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common, - * but it is (strictly) malformed, because the first * is eliding both - * the Setwidth and the Addstyle fields. If the Addstyle field is a - * number, then assume the above incorrect form was used and shift all - * the rest of the fields up by one, so the number gets interpreted - * as a pixelsize. This fix is so that we don't get a million reports - * that "it works under X, but gives a syntax error under Windows". - */ - - if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) { - if (atoi(field[XLFD_ADD_STYLE]) != 0) { - for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) { - field[j + 1] = field[j]; - } - field[XLFD_ADD_STYLE] = NULL; - i++; - } - } - - /* - * Bail if we don't have enough of the fields (up to pointsize). - */ - - if (i < XLFD_FAMILY) { - Tcl_DStringFree(&ds); - return TCL_ERROR; - } - - if (FieldSpecified(field[XLFD_FOUNDRY])) { - xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]); - } - - if (FieldSpecified(field[XLFD_FAMILY])) { - xaPtr->fa.family = Tk_GetUid(field[XLFD_FAMILY]); - } - if (FieldSpecified(field[XLFD_WEIGHT])) { - xaPtr->fa.weight = TkFindStateNum(NULL, NULL, xlfdWeightMap, - field[XLFD_WEIGHT]); - } - if (FieldSpecified(field[XLFD_SLANT])) { - xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap, - field[XLFD_SLANT]); - if (xaPtr->slant == TK_FS_ROMAN) { - xaPtr->fa.slant = TK_FS_ROMAN; - } else { - xaPtr->fa.slant = TK_FS_ITALIC; - } - } - if (FieldSpecified(field[XLFD_SETWIDTH])) { - xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap, - field[XLFD_SETWIDTH]); - } - - /* XLFD_ADD_STYLE ignored. */ - - /* - * Pointsize in tenths of a point, but treat it as tenths of a pixel. - */ - - if (FieldSpecified(field[XLFD_POINT_SIZE])) { - if (field[XLFD_POINT_SIZE][0] == '[') { - /* - * Some X fonts have the point size specified as follows: - * - * [ N1 N2 N3 N4 ] - * - * where N1 is the point size (in points, not decipoints!), and - * N2, N3, and N4 are some additional numbers that I don't know - * the purpose of, so I ignore them. - */ - - xaPtr->fa.pointsize = atoi(field[XLFD_POINT_SIZE] + 1); - } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE], - &xaPtr->fa.pointsize) == TCL_OK) { - xaPtr->fa.pointsize /= 10; - } else { - return TCL_ERROR; - } - } - - /* - * Pixel height of font. If specified, overrides pointsize. - */ - - if (FieldSpecified(field[XLFD_PIXEL_SIZE])) { - if (field[XLFD_PIXEL_SIZE][0] == '[') { - /* - * Some X fonts have the pixel size specified as follows: - * - * [ N1 N2 N3 N4 ] - * - * where N1 is the pixel size, and where N2, N3, and N4 - * are some additional numbers that I don't know - * the purpose of, so I ignore them. - */ - - xaPtr->fa.pointsize = atoi(field[XLFD_PIXEL_SIZE] + 1); - } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE], - &xaPtr->fa.pointsize) != TCL_OK) { - return TCL_ERROR; - } - } - - xaPtr->fa.pointsize = -xaPtr->fa.pointsize; - - /* XLFD_RESOLUTION_X ignored. */ - - /* XLFD_RESOLUTION_Y ignored. */ - - /* XLFD_SPACING ignored. */ - - /* XLFD_AVERAGE_WIDTH ignored. */ - - if (FieldSpecified(field[XLFD_REGISTRY])) { - xaPtr->charset = TkFindStateNum(NULL, NULL, xlfdCharsetMap, - field[XLFD_REGISTRY]); - } - if (FieldSpecified(field[XLFD_ENCODING])) { - xaPtr->encoding = atoi(field[XLFD_ENCODING]); - } - - Tcl_DStringFree(&ds); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * FieldSpecified -- - * - * Helper function for TkParseXLFD(). Determines if a field in the - * XLFD was set to a non-null, non-don't-care value. - * - * Results: - * The return value is 0 if the field in the XLFD was not set and - * should be ignored, non-zero otherwise. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -FieldSpecified(field) - CONST char *field; /* The field of the XLFD to check. Strictly - * speaking, only when the string is "*" does it mean - * don't-care. However, an unspecified or question - * mark is also interpreted as don't-care. */ -{ - char ch; - - if (field == NULL) { - return 0; - } - ch = field[0]; - return (ch != '*' && ch != '?'); -} - -/* - *--------------------------------------------------------------------------- - * - * NewChunk -- - * - * Helper function for Tk_ComputeTextLayout(). Encapsulates a - * measured set of characters in a chunk that can be quickly - * drawn. - * - * Results: - * A pointer to the new chunk in the text layout. - * - * Side effects: - * The text layout is reallocated to hold more chunks as necessary. - * - * Currently, Tk_ComputeTextLayout() stores contiguous ranges of - * "normal" characters in a chunk, along with individual tab - * and newline chars in their own chunks. All characters in the - * text layout are accounted for. - * - *--------------------------------------------------------------------------- - */ -static LayoutChunk * -NewChunk(layoutPtrPtr, maxPtr, start, numChars, curX, newX, y) - TextLayout **layoutPtrPtr; - int *maxPtr; - CONST char *start; - int numChars; - int curX; - int newX; - int y; -{ - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - int maxChunks; - size_t s; - - layoutPtr = *layoutPtrPtr; - maxChunks = *maxPtr; - if (layoutPtr->numChunks == maxChunks) { - maxChunks *= 2; - s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); - - *layoutPtrPtr = layoutPtr; - *maxPtr = maxChunks; - } - chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; - chunkPtr->start = start; - chunkPtr->numChars = numChars; - chunkPtr->numDisplayChars = numChars; - chunkPtr->x = curX; - chunkPtr->y = y; - chunkPtr->totalWidth = newX - curX; - chunkPtr->displayWidth = newX - curX; - layoutPtr->numChunks++; - - return chunkPtr; -} - diff --git a/generic/tkFont.h b/generic/tkFont.h deleted file mode 100644 index e2a7e04..0000000 --- a/generic/tkFont.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * tkFont.h -- - * - * Declarations for interfaces between the generic and platform- - * specific parts of the font package. This information is not - * visible outside of the font package. - * - * Copyright (c) 1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFont.h,v 1.4 1998/09/14 18:23:10 stanton Exp $ - */ - -#ifndef _TKFONT -#define _TKFONT - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * The following structure keeps track of the attributes of a font. It can - * be used to keep track of either the desired attributes or the actual - * attributes gotten when the font was instantiated. - */ - -typedef struct TkFontAttributes { - Tk_Uid family; /* Font family. The most important field. */ - int pointsize; /* Pointsize of font, 0 for default size, or - * negative number meaning pixel size. */ - int weight; /* Weight flag; see below for def'n. */ - int slant; /* Slant flag; see below for def'n. */ - int underline; /* Non-zero for underline font. */ - int overstrike; /* Non-zero for overstrike font. */ -} TkFontAttributes; - -/* - * Possible values for the "weight" field in a TkFontAttributes structure. - * Weight is a subjective term and depends on what the company that created - * the font considers bold. - */ - -#define TK_FW_NORMAL 0 -#define TK_FW_BOLD 1 - -#define TK_FW_UNKNOWN -1 /* Unknown weight. This value is used for - * error checking and is never actually stored - * in the weight field. */ - -/* - * Possible values for the "slant" field in a TkFontAttributes structure. - */ - -#define TK_FS_ROMAN 0 -#define TK_FS_ITALIC 1 -#define TK_FS_OBLIQUE 2 /* This value is only used when parsing X - * font names to determine the closest - * match. It is only stored in the - * XLFDAttributes structure, never in the - * slant field of the TkFontAttributes. */ - -#define TK_FS_UNKNOWN -1 /* Unknown slant. This value is used for - * error checking and is never actually stored - * in the slant field. */ - -/* - * The following structure keeps track of the metrics for an instantiated - * font. The metrics are the physical properties of the font itself. - */ - -typedef struct TkFontMetrics { - int ascent; /* From baseline to top of font. */ - int descent; /* From baseline to bottom of font. */ - int maxWidth; /* Width of widest character in font. */ - int fixed; /* Non-zero if this is a fixed-width font, - * 0 otherwise. */ -} TkFontMetrics; - -/* - * The following structure is used to keep track of the generic information - * about a font. Each platform-specific font is represented by a structure - * with the following structure at its beginning, plus any platform- - * specific stuff after that. - */ - -typedef struct TkFont { - /* - * Fields used and maintained exclusively by generic code. - */ - - int refCount; /* Number of users of the TkFont. */ - Tcl_HashEntry *cacheHashPtr;/* Entry in font cache for this structure, - * used when deleting it. */ - Tcl_HashEntry *namedHashPtr;/* Pointer to hash table entry that - * corresponds to the named font that the - * tkfont was based on, or NULL if the tkfont - * was not based on a named font. */ - int tabWidth; /* Width of tabs in this font (pixels). */ - int underlinePos; /* Offset from baseline to origin of - * underline bar (used for drawing underlines - * on a non-underlined font). */ - int underlineHeight; /* Height of underline bar (used for drawing - * underlines on a non-underlined font). */ - - /* - * Fields in the generic font structure that are filled in by - * platform-specific code. - */ - - Font fid; /* For backwards compatibility with XGCValues - * structures. Remove when TkGCValues is - * implemented. */ - TkFontAttributes fa; /* Actual font attributes obtained when the - * the font was created, as opposed to the - * desired attributes passed in to - * TkpGetFontFromAttributes(). The desired - * metrics can be determined from the string - * that was used to create this font. */ - TkFontMetrics fm; /* Font metrics determined when font was - * created. */ -} TkFont; - -/* - * The following structure is used to return attributes when parsing an - * XLFD. The extra information is of interest to the Unix-specific code - * when attempting to find the closest matching font. - */ - -typedef struct TkXLFDAttributes { - TkFontAttributes fa; /* Standard set of font attributes. */ - Tk_Uid foundry; /* The foundry of the font. */ - int slant; /* The tristate value for the slant, which - * is significant under X. */ - int setwidth; /* The proportionate width, see below for - * definition. */ - int charset; /* The character set encoding (the glyph - * family), see below for definition. */ - int encoding; /* Variations within a charset for the - * glyphs above character 127. */ -} TkXLFDAttributes; - -/* - * Possible values for the "setwidth" field in a TkXLFDAttributes structure. - * The setwidth is whether characters are considered wider or narrower than - * normal. - */ - -#define TK_SW_NORMAL 0 -#define TK_SW_CONDENSE 1 -#define TK_SW_EXPAND 2 -#define TK_SW_UNKNOWN 3 /* Unknown setwidth. This value may be - * stored in the setwidth field. */ - -/* - * Possible values for the "charset" field in a TkXLFDAttributes structure. - * The charset is the set of glyphs that are used in the font. - */ - -#define TK_CS_NORMAL 0 -#define TK_CS_SYMBOL 1 -#define TK_CS_OTHER 2 - -/* - * The following defines specify the meaning of the fields in a fully - * qualified XLFD. - */ - -#define XLFD_FOUNDRY 0 -#define XLFD_FAMILY 1 -#define XLFD_WEIGHT 2 -#define XLFD_SLANT 3 -#define XLFD_SETWIDTH 4 -#define XLFD_ADD_STYLE 5 -#define XLFD_PIXEL_SIZE 6 -#define XLFD_POINT_SIZE 7 -#define XLFD_RESOLUTION_X 8 -#define XLFD_RESOLUTION_Y 9 -#define XLFD_SPACING 10 -#define XLFD_AVERAGE_WIDTH 11 -#define XLFD_REGISTRY 12 -#define XLFD_ENCODING 13 -#define XLFD_NUMFIELDS 14 /* Number of fields in XLFD. */ - -/* - * Exported from generic code to platform-specific code. - */ - -EXTERN int TkCreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, CONST char *name, - TkFontAttributes *faPtr)); -EXTERN void TkInitFontAttributes _ANSI_ARGS_(( - TkFontAttributes *faPtr)); -EXTERN int TkParseXLFD _ANSI_ARGS_((CONST char *string, - TkXLFDAttributes *xaPtr)); - -/* - * Common APIs exported to tkFont.c from all platform-specific - * implementations. - */ - -EXTERN void TkpDeleteFont _ANSI_ARGS_((TkFont *tkFontPtr)); -EXTERN TkFont * TkpGetFontFromAttributes _ANSI_ARGS_(( - TkFont *tkFontPtr, Tk_Window tkwin, - CONST TkFontAttributes *faPtr)); -EXTERN void TkpGetFontFamilies _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN TkFont * TkpGetNativeFont _ANSI_ARGS_((Tk_Window tkwin, - CONST char *name)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKFONT */ diff --git a/generic/tkFrame.c b/generic/tkFrame.c deleted file mode 100644 index 18ce64f..0000000 --- a/generic/tkFrame.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * tkFrame.c -- - * - * This module implements "frame" and "toplevel" widgets for - * the Tk toolkit. Frames are windows with a background color - * and possibly a 3-D effect, but not much else in the way of - * attributes. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkFrame.c,v 1.2 1998/09/14 18:23:10 stanton Exp $ - */ - -#include "default.h" -#include "tkPort.h" -#include "tkInt.h" - -/* - * A data structure of the following type is kept for each - * frame that currently exists for this process: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the frame. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up. */ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with widget. Used - * to delete widget command. */ - Tcl_Command widgetCmd; /* Token for frame's widget command. */ - char *className; /* Class name for widget (from configuration - * option). Malloc-ed. */ - int mask; /* Either FRAME or TOPLEVEL; used to select - * which configuration options are valid for - * widget. */ - char *screenName; /* Screen on which widget is created. Non-null - * only for top-levels. Malloc-ed, may be - * NULL. */ - char *visualName; /* Textual description of visual for window, - * from -visual option. Malloc-ed, may be - * NULL. */ - char *colormapName; /* Textual description of colormap for window, - * from -colormap option. Malloc-ed, may be - * NULL. */ - char *menuName; /* Textual description of menu to use for - * menubar. Malloc-ed, may be NULL. */ - Colormap colormap; /* If not None, identifies a colormap - * allocated for this window, which must be - * freed when the window is deleted. */ - Tk_3DBorder border; /* Structure used to draw 3-D border and - * background. NULL means no background - * or border. */ - int borderWidth; /* Width of 3-D border (if any). */ - int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int width; /* Width to request for window. <= 0 means - * don't request any size. */ - int height; /* Height to request for window. <= 0 means - * don't request any size. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int isContainer; /* 1 means this window is a container, 0 means - * that it isn't. */ - char *useThis; /* If the window is embedded, this points to - * the name of the window in which it is - * embedded (malloc'ed). For non-embedded - * windows this is NULL. */ - int flags; /* Various flags; see below for - * definitions. */ -} Frame; - -/* - * Flag bits for frames: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * GOT_FOCUS: Non-zero means this widget currently - * has the input focus. - */ - -#define REDRAW_PENDING 1 -#define GOT_FOCUS 4 - -/* - * The following flag bits are used so that there can be separate - * defaults for some configuration options for frames and toplevels. - */ - -#define FRAME TK_CONFIG_USER_BIT -#define TOPLEVEL (TK_CONFIG_USER_BIT << 1) -#define BOTH (FRAME | TOPLEVEL) - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border), - BOTH|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_FRAME_BG_MONO, Tk_Offset(Frame, border), - BOTH|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, BOTH}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, BOTH}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), BOTH}, - {TK_CONFIG_STRING, "-class", "class", "Class", - DEF_FRAME_CLASS, Tk_Offset(Frame, className), FRAME}, - {TK_CONFIG_STRING, "-class", "class", "Class", - DEF_TOPLEVEL_CLASS, Tk_Offset(Frame, className), TOPLEVEL}, - {TK_CONFIG_STRING, "-colormap", "colormap", "Colormap", - DEF_FRAME_COLORMAP, Tk_Offset(Frame, colormapName), - BOTH|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-container", "container", "Container", - DEF_FRAME_CONTAINER, Tk_Offset(Frame, isContainer), BOTH}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), BOTH|TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-height", "height", "Height", - DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), BOTH}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG, - Tk_Offset(Frame, highlightBgColorPtr), BOTH}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_FRAME_HIGHLIGHT, Tk_Offset(Frame, highlightColorPtr), BOTH}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_FRAME_HIGHLIGHT_WIDTH, Tk_Offset(Frame, highlightWidth), BOTH}, - {TK_CONFIG_STRING, "-menu", "menu", "Menu", - DEF_TOPLEVEL_MENU, Tk_Offset(Frame, menuName), - TOPLEVEL|TK_CONFIG_NULL_OK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), BOTH}, - {TK_CONFIG_STRING, "-screen", "screen", "Screen", - DEF_TOPLEVEL_SCREEN, Tk_Offset(Frame, screenName), - TOPLEVEL|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_FRAME_TAKE_FOCUS, Tk_Offset(Frame, takeFocus), - BOTH|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-use", "use", "Use", - DEF_FRAME_USE, Tk_Offset(Frame, useThis), TOPLEVEL|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-visual", "visual", "Visual", - DEF_FRAME_VISUAL, Tk_Offset(Frame, visualName), - BOTH|TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_FRAME_WIDTH, Tk_Offset(Frame, width), BOTH}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp, - Frame *framePtr, int argc, char **argv, - int flags)); -static void DestroyFrame _ANSI_ARGS_((char *memPtr)); -static void DisplayFrame _ANSI_ARGS_((ClientData clientData)); -static void FrameCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void FrameEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void MapFrame _ANSI_ARGS_((ClientData clientData)); - -/* - *-------------------------------------------------------------- - * - * Tk_FrameCmd, Tk_ToplevelCmd -- - * - * These procedures are invoked to process the "frame" and - * "toplevel" Tcl commands. See the user documentation for - * details on what they do. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. These procedures are just wrappers; - * they call ButtonCreate to do all of the real work. - * - *-------------------------------------------------------------- - */ - -int -Tk_FrameCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return TkCreateFrame(clientData, interp, argc, argv, 0, (char *) NULL); -} - -int -Tk_ToplevelCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - return TkCreateFrame(clientData, interp, argc, argv, 1, (char *) NULL); -} - -/* - *-------------------------------------------------------------- - * - * TkFrameCreate -- - * - * This procedure is invoked to process the "frame" and "toplevel" - * Tcl commands; it is also invoked directly by Tk_Init to create - * a new main window. See the user documentation for the "frame" - * and "toplevel" commands for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) - ClientData clientData; /* Main window associated with interpreter. - * If we're called by Tk_Init to create a - * new application, then this is NULL. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ - int toplevel; /* Non-zero means create a toplevel window, - * zero means create a frame. */ - char *appName; /* Should only be non-NULL if clientData is - * NULL: gives the base name to use for the - * new application. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - Frame *framePtr; - Tk_Window new; - char *className, *screenName, *visualName, *colormapName, *arg, *useOption; - int i, c, length, depth; - unsigned int mask; - Colormap colormap; - Visual *visual; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Pre-process the argument list. Scan through it to find any - * "-class", "-screen", "-visual", and "-colormap" options. These - * arguments need to be processed specially, before the window - * is configured using the usual Tk mechanisms. - */ - - className = colormapName = screenName = visualName = useOption = NULL; - colormap = None; - for (i = 2; i < argc; i += 2) { - arg = argv[i]; - length = strlen(arg); - if (length < 2) { - continue; - } - c = arg[1]; - if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0) - && (length >= 3)) { - className = argv[i+1]; - } else if ((c == 'c') - && (strncmp(arg, "-colormap", strlen(arg)) == 0)) { - colormapName = argv[i+1]; - } else if ((c == 's') && toplevel - && (strncmp(arg, "-screen", strlen(arg)) == 0)) { - screenName = argv[i+1]; - } else if ((c == 'u') && toplevel - && (strncmp(arg, "-use", strlen(arg)) == 0)) { - useOption = argv[i+1]; - } else if ((c == 'v') - && (strncmp(arg, "-visual", strlen(arg)) == 0)) { - visualName = argv[i+1]; - } - } - - /* - * Create the window, and deal with the special options -use, - * -classname, -colormap, -screenname, and -visual. These options - * must be handle before calling ConfigureFrame below, and they must - * also be processed in a particular order, for the following - * reasons: - * 1. Must set the window's class before calling ConfigureFrame, - * so that unspecified options are looked up in the option - * database using the correct class. - * 2. Must set visual information before calling ConfigureFrame - * so that colors are allocated in a proper colormap. - * 3. Must call TkpUseWindow before setting non-default visual - * information, since TkpUseWindow changes the defaults. - */ - - if (screenName == NULL) { - screenName = (toplevel) ? "" : NULL; - } - if (tkwin != NULL) { - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName); - } else { - /* - * We were called from Tk_Init; create a new application. - */ - - if (appName == NULL) { - panic("TkCreateFrame didn't get application name"); - } - new = TkCreateMainWindow(interp, screenName, appName); - } - if (new == NULL) { - goto error; - } - if (className == NULL) { - className = Tk_GetOption(new, "class", "Class"); - if (className == NULL) { - className = (toplevel) ? "Toplevel" : "Frame"; - } - } - Tk_SetClass(new, className); - if (useOption == NULL) { - useOption = Tk_GetOption(new, "use", "Use"); - } - if (useOption != NULL) { - if (TkpUseWindow(interp, new, useOption) != TCL_OK) { - goto error; - } - } - if (visualName == NULL) { - visualName = Tk_GetOption(new, "visual", "Visual"); - } - if (colormapName == NULL) { - colormapName = Tk_GetOption(new, "colormap", "Colormap"); - } - if (visualName != NULL) { - visual = Tk_GetVisual(interp, new, visualName, &depth, - (colormapName == NULL) ? &colormap : (Colormap *) NULL); - if (visual == NULL) { - goto error; - } - Tk_SetWindowVisual(new, visual, depth, colormap); - } - if (colormapName != NULL) { - colormap = Tk_GetColormap(interp, new, colormapName); - if (colormap == None) { - goto error; - } - Tk_SetWindowColormap(new, colormap); - } - - /* - * For top-level windows, provide an initial geometry request of - * 200x200, just so the window looks nicer on the screen if it - * doesn't request a size for itself. - */ - - if (toplevel) { - Tk_GeometryRequest(new, 200, 200); - } - - /* - * Create the widget record, process configuration options, and - * create event handlers. Then fill in a few additional fields - * in the widget record from the special options. - */ - - framePtr = (Frame *) ckalloc(sizeof(Frame)); - framePtr->tkwin = new; - framePtr->display = Tk_Display(new); - framePtr->interp = interp; - framePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(new), FrameWidgetCmd, - (ClientData) framePtr, FrameCmdDeletedProc); - framePtr->className = NULL; - framePtr->mask = (toplevel) ? TOPLEVEL : FRAME; - framePtr->screenName = NULL; - framePtr->visualName = NULL; - framePtr->colormapName = NULL; - framePtr->colormap = colormap; - framePtr->border = NULL; - framePtr->borderWidth = 0; - framePtr->relief = TK_RELIEF_FLAT; - framePtr->highlightWidth = 0; - framePtr->highlightBgColorPtr = NULL; - framePtr->highlightColorPtr = NULL; - framePtr->width = 0; - framePtr->height = 0; - framePtr->cursor = None; - framePtr->takeFocus = NULL; - framePtr->isContainer = 0; - framePtr->useThis = NULL; - framePtr->flags = 0; - framePtr->menuName = NULL; - - /* - * Store backreference to frame widget in window structure. - */ - TkSetClassProcs(new, NULL, (ClientData) framePtr); - - mask = ExposureMask | StructureNotifyMask | FocusChangeMask; - if (toplevel) { - mask |= ActivateMask; - } - Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData) framePtr); - if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - if ((framePtr->isContainer)) { - if (framePtr->useThis == NULL) { - TkpMakeContainer(framePtr->tkwin); - } else { - Tcl_AppendResult(interp,"A window cannot have both the -use ", - "and the -container option set."); - return TCL_ERROR; - } - } - if (toplevel) { - Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr); - } - interp->result = Tk_PathName(new); - return TCL_OK; - - error: - if (new != NULL) { - Tk_DestroyWindow(new); - } - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * FrameWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a frame widget. See the user - * documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -FrameWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about frame widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Frame *framePtr = (Frame *) clientData; - int result; - size_t length; - int c, i; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) framePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, (char *) NULL, framePtr->mask); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); - } else { - /* - * Don't allow the options -class, -colormap, -container, - * -newcmap, -screen, -use, or -visual to be changed. - */ - - for (i = 2; i < argc; i++) { - length = strlen(argv[i]); - if (length < 2) { - continue; - } - c = argv[i][1]; - if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0) - && (length >= 2)) - || ((c == 'c') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-colormap", length) == 0) - && (length >= 3)) - || ((c == 'c') - && (strncmp(argv[i], "-container", length) == 0) - && (length >= 3)) - || ((c == 's') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-screen", length) == 0)) - || ((c == 'u') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-use", length) == 0)) - || ((c == 'v') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-visual", length) == 0))) { - Tcl_AppendResult(interp, "can't modify ", argv[i], - " option after widget is created", (char *) NULL); - result = TCL_ERROR; - goto done; - } - } - result = ConfigureFrame(interp, framePtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - result = TCL_ERROR; - } - - done: - Tcl_Release((ClientData) framePtr); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyFrame -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a frame at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the frame is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyFrame(memPtr) - char *memPtr; /* Info about frame widget. */ -{ - register Frame *framePtr = (Frame *) memPtr; - - Tk_FreeOptions(configSpecs, (char *) framePtr, framePtr->display, - framePtr->mask); - if (framePtr->colormap != None) { - Tk_FreeColormap(framePtr->display, framePtr->colormap); - } - ckfree((char *) framePtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureFrame -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a frame widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for framePtr; old resources get freed, if there - * were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureFrame(interp, framePtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register Frame *framePtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - char *oldMenuName; - - /* - * Need the old menubar name for the menu code to delete it. - */ - - if (framePtr->menuName == NULL) { - oldMenuName = NULL; - } else { - oldMenuName = ckalloc(strlen(framePtr->menuName) + 1); - strcpy(oldMenuName, framePtr->menuName); - } - - if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs, - argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) { - return TCL_ERROR; - } - - if (((oldMenuName == NULL) && (framePtr->menuName != NULL)) - || ((oldMenuName != NULL) && (framePtr->menuName == NULL)) - || ((oldMenuName != NULL) && (framePtr->menuName != NULL) - && strcmp(oldMenuName, framePtr->menuName) != 0)) { - TkSetWindowMenuBar(interp, framePtr->tkwin, oldMenuName, - framePtr->menuName); - } - - if (framePtr->border != NULL) { - Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border); - } else { - Tk_SetWindowBackgroundPixmap(framePtr->tkwin, None); - } - - if (framePtr->highlightWidth < 0) { - framePtr->highlightWidth = 0; - } - Tk_SetInternalBorder(framePtr->tkwin, - framePtr->borderWidth + framePtr->highlightWidth); - if ((framePtr->width > 0) || (framePtr->height > 0)) { - Tk_GeometryRequest(framePtr->tkwin, framePtr->width, - framePtr->height); - } - - if (oldMenuName != NULL) { - ckfree(oldMenuName); - } - - if (Tk_IsMapped(framePtr->tkwin)) { - if (!(framePtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr); - } - framePtr->flags |= REDRAW_PENDING; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * DisplayFrame -- - * - * This procedure is invoked to display a frame widget. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the frame in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -static void -DisplayFrame(clientData) - ClientData clientData; /* Information about widget. */ -{ - register Frame *framePtr = (Frame *) clientData; - register Tk_Window tkwin = framePtr->tkwin; - GC gc; - - framePtr->flags &= ~REDRAW_PENDING; - if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin) - || framePtr->isContainer) { - return; - } - - if (framePtr->border != NULL) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), - framePtr->border, framePtr->highlightWidth, - framePtr->highlightWidth, - Tk_Width(tkwin) - 2*framePtr->highlightWidth, - Tk_Height(tkwin) - 2*framePtr->highlightWidth, - framePtr->borderWidth, framePtr->relief); - } - if (framePtr->highlightWidth != 0) { - if (framePtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(framePtr->highlightColorPtr, - Tk_WindowId(tkwin)); - } else { - gc = Tk_GCForColor(framePtr->highlightBgColorPtr, - Tk_WindowId(tkwin)); - } - Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth, - Tk_WindowId(tkwin)); - } -} - -/* - *-------------------------------------------------------------- - * - * FrameEventProc -- - * - * This procedure is invoked by the Tk dispatcher on - * structure changes to a frame. For frames with 3D - * borders, this procedure is also invoked for exposures. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -FrameEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - register XEvent *eventPtr; /* Information about event. */ -{ - register Frame *framePtr = (Frame *) clientData; - - if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) - || (eventPtr->type == ConfigureNotify)) { - goto redraw; - } else if (eventPtr->type == DestroyNotify) { - if (framePtr->menuName != NULL) { - TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, - framePtr->menuName, NULL); - ckfree(framePtr->menuName); - framePtr->menuName = NULL; - } - if (framePtr->tkwin != NULL) { - - /* - * If this window is a container, then this event could be - * coming from the embedded application, in which case - * Tk_DestroyWindow hasn't been called yet. When Tk_DestroyWindow - * is called later, then another destroy event will be generated. - * We need to be sure we ignore the second event, since the frame - * could be gone by then. To do so, delete the event handler - * explicitly (normally it's done implicitly by Tk_DestroyWindow). - */ - - Tk_DeleteEventHandler(framePtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - FrameEventProc, (ClientData) framePtr); - framePtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(framePtr->interp, framePtr->widgetCmd); - } - if (framePtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayFrame, (ClientData) framePtr); - } - Tcl_CancelIdleCall(MapFrame, (ClientData) framePtr); - Tcl_EventuallyFree((ClientData) framePtr, DestroyFrame); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - framePtr->flags |= GOT_FOCUS; - if (framePtr->highlightWidth > 0) { - goto redraw; - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - framePtr->flags &= ~GOT_FOCUS; - if (framePtr->highlightWidth > 0) { - goto redraw; - } - } - } else if (eventPtr->type == ActivateNotify) { - TkpSetMainMenubar(framePtr->interp, framePtr->tkwin, - framePtr->menuName); - } - return; - - redraw: - if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr); - framePtr->flags |= REDRAW_PENDING; - } -} - -/* - *---------------------------------------------------------------------- - * - * FrameCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -FrameCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - Frame *framePtr = (Frame *) clientData; - Tk_Window tkwin = framePtr->tkwin; - - if (framePtr->menuName != NULL) { - TkSetWindowMenuBar(framePtr->interp, framePtr->tkwin, - framePtr->menuName, NULL); - ckfree(framePtr->menuName); - framePtr->menuName = NULL; - } - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - framePtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *---------------------------------------------------------------------- - * - * MapFrame -- - * - * This procedure is invoked as a when-idle handler to map a - * newly-created top-level frame. - * - * Results: - * None. - * - * Side effects: - * The frame given by the clientData argument is mapped. - * - *---------------------------------------------------------------------- - */ - -static void -MapFrame(clientData) - ClientData clientData; /* Pointer to frame structure. */ -{ - Frame *framePtr = (Frame *) clientData; - - /* - * Wait for all other background events to be processed before - * mapping window. This ensures that the window's correct geometry - * will have been determined before it is first mapped, so that the - * window manager doesn't get a false idea of its desired geometry. - */ - - Tcl_Preserve((ClientData) framePtr); - while (1) { - if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) { - break; - } - - /* - * After each event, make sure that the window still exists - * and quit if the window has been destroyed. - */ - - if (framePtr->tkwin == NULL) { - Tcl_Release((ClientData) framePtr); - return; - } - } - Tk_MapWindow(framePtr->tkwin); - Tcl_Release((ClientData) framePtr); -} - -/* - *-------------------------------------------------------------- - * - * TkInstallFrameMenu -- - * - * This function is needed when a Windows HWND is created - * and a menubar has been set to the window with a system - * menu. It notifies the menu package so that the system - * menu can be rebuilt. - * - * Results: - * None. - * - * Side effects: - * The system menu (if any) is created for the menubar - * associated with this frame. - * - *-------------------------------------------------------------- - */ - -void -TkInstallFrameMenu(tkwin) - Tk_Window tkwin; /* The window that was just created. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - - if (winPtr->mainPtr != NULL) { - Frame *framePtr; - framePtr = (Frame*) winPtr->instanceData; - TkpMenuNotifyToplevelCreate(winPtr->mainPtr->interp, - framePtr->menuName); - } -} diff --git a/generic/tkGC.c b/generic/tkGC.c deleted file mode 100644 index dd53e32..0000000 --- a/generic/tkGC.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * tkGC.c -- - * - * This file maintains a database of read-only graphics contexts - * for the Tk toolkit, in order to allow GC's to be shared. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkGC.c,v 1.2 1998/09/14 18:23:11 stanton Exp $ - */ - -#include "tkPort.h" -#include "tk.h" - -/* - * One of the following data structures exists for each GC that is - * currently active. The structure is indexed with two hash tables, - * one based on the values in the graphics context and the other - * based on the display and GC identifier. - */ - -typedef struct { - GC gc; /* Graphics context. */ - Display *display; /* Display to which gc belongs. */ - int refCount; /* Number of active uses of gc. */ - Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting - * this structure). */ -} TkGC; - -/* - * Hash table to map from a GC's values to a TkGC structure describing - * a GC with those values (used by Tk_GetGC). - */ - -static Tcl_HashTable valueTable; -typedef struct { - XGCValues values; /* Desired values for GC. */ - Display *display; /* Display for which GC is valid. */ - int screenNum; /* screen number of display */ - int depth; /* and depth for which GC is valid. */ -} ValueKey; - -/* - * Hash table for <display + GC> -> TkGC mapping. This table is used by - * Tk_FreeGC. - */ - -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which GC was allocated. */ - GC gc; /* X's identifier for GC. */ -} IdKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static void GCInit _ANSI_ARGS_((void)); - -/* - *---------------------------------------------------------------------- - * - * Tk_GetGC -- - * - * Given a desired set of values for a graphics context, find - * a read-only graphics context with the desired values. - * - * Results: - * The return value is the X identifer for the desired graphics - * context. The caller should never modify this GC, and should - * call Tk_FreeGC when the GC is no longer needed. - * - * Side effects: - * The GC is added to an internal database with a reference count. - * For each call to this procedure, there should eventually be a call - * to Tk_FreeGC, so that the database can be cleaned up when GC's - * aren't needed anymore. - * - *---------------------------------------------------------------------- - */ - -GC -Tk_GetGC(tkwin, valueMask, valuePtr) - Tk_Window tkwin; /* Window in which GC will be used. */ - register unsigned long valueMask; - /* 1 bits correspond to values specified - * in *valuesPtr; other values are set - * from defaults. */ - register XGCValues *valuePtr; - /* Values are specified here for bits set - * in valueMask. */ -{ - ValueKey valueKey; - IdKey idKey; - Tcl_HashEntry *valueHashPtr, *idHashPtr; - register TkGC *gcPtr; - int new; - Drawable d, freeDrawable; - - if (!initialized) { - GCInit(); - } - - /* - * Must zero valueKey at start to clear out pad bytes that may be - * part of structure on some systems. - */ - - memset((VOID *) &valueKey, 0, sizeof(valueKey)); - - /* - * First, check to see if there's already a GC that will work - * for this request (exact matches only, sorry). - */ - - if (valueMask & GCFunction) { - valueKey.values.function = valuePtr->function; - } else { - valueKey.values.function = GXcopy; - } - if (valueMask & GCPlaneMask) { - valueKey.values.plane_mask = valuePtr->plane_mask; - } else { - valueKey.values.plane_mask = (unsigned) ~0; - } - if (valueMask & GCForeground) { - valueKey.values.foreground = valuePtr->foreground; - } else { - valueKey.values.foreground = 0; - } - if (valueMask & GCBackground) { - valueKey.values.background = valuePtr->background; - } else { - valueKey.values.background = 1; - } - if (valueMask & GCLineWidth) { - valueKey.values.line_width = valuePtr->line_width; - } else { - valueKey.values.line_width = 0; - } - if (valueMask & GCLineStyle) { - valueKey.values.line_style = valuePtr->line_style; - } else { - valueKey.values.line_style = LineSolid; - } - if (valueMask & GCCapStyle) { - valueKey.values.cap_style = valuePtr->cap_style; - } else { - valueKey.values.cap_style = CapButt; - } - if (valueMask & GCJoinStyle) { - valueKey.values.join_style = valuePtr->join_style; - } else { - valueKey.values.join_style = JoinMiter; - } - if (valueMask & GCFillStyle) { - valueKey.values.fill_style = valuePtr->fill_style; - } else { - valueKey.values.fill_style = FillSolid; - } - if (valueMask & GCFillRule) { - valueKey.values.fill_rule = valuePtr->fill_rule; - } else { - valueKey.values.fill_rule = EvenOddRule; - } - if (valueMask & GCArcMode) { - valueKey.values.arc_mode = valuePtr->arc_mode; - } else { - valueKey.values.arc_mode = ArcPieSlice; - } - if (valueMask & GCTile) { - valueKey.values.tile = valuePtr->tile; - } else { - valueKey.values.tile = None; - } - if (valueMask & GCStipple) { - valueKey.values.stipple = valuePtr->stipple; - } else { - valueKey.values.stipple = None; - } - if (valueMask & GCTileStipXOrigin) { - valueKey.values.ts_x_origin = valuePtr->ts_x_origin; - } else { - valueKey.values.ts_x_origin = 0; - } - if (valueMask & GCTileStipYOrigin) { - valueKey.values.ts_y_origin = valuePtr->ts_y_origin; - } else { - valueKey.values.ts_y_origin = 0; - } - if (valueMask & GCFont) { - valueKey.values.font = valuePtr->font; - } else { - valueKey.values.font = None; - } - if (valueMask & GCSubwindowMode) { - valueKey.values.subwindow_mode = valuePtr->subwindow_mode; - } else { - valueKey.values.subwindow_mode = ClipByChildren; - } - if (valueMask & GCGraphicsExposures) { - valueKey.values.graphics_exposures = valuePtr->graphics_exposures; - } else { - valueKey.values.graphics_exposures = True; - } - if (valueMask & GCClipXOrigin) { - valueKey.values.clip_x_origin = valuePtr->clip_x_origin; - } else { - valueKey.values.clip_x_origin = 0; - } - if (valueMask & GCClipYOrigin) { - valueKey.values.clip_y_origin = valuePtr->clip_y_origin; - } else { - valueKey.values.clip_y_origin = 0; - } - if (valueMask & GCClipMask) { - valueKey.values.clip_mask = valuePtr->clip_mask; - } else { - valueKey.values.clip_mask = None; - } - if (valueMask & GCDashOffset) { - valueKey.values.dash_offset = valuePtr->dash_offset; - } else { - valueKey.values.dash_offset = 0; - } - if (valueMask & GCDashList) { - valueKey.values.dashes = valuePtr->dashes; - } else { - valueKey.values.dashes = 4; - } - valueKey.display = Tk_Display(tkwin); - valueKey.screenNum = Tk_ScreenNumber(tkwin); - valueKey.depth = Tk_Depth(tkwin); - valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new); - if (!new) { - gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr); - gcPtr->refCount++; - return gcPtr->gc; - } - - /* - * No GC is currently available for this set of values. Allocate a - * new GC and add a new structure to the database. - */ - - gcPtr = (TkGC *) ckalloc(sizeof(TkGC)); - - /* - * Find or make a drawable to use to specify the screen and depth - * of the GC. We may have to make a small pixmap, to avoid doing - * Tk_MakeWindowExist on the window. - */ - - freeDrawable = None; - if (Tk_WindowId(tkwin) != None) { - d = Tk_WindowId(tkwin); - } else if (valueKey.depth == - DefaultDepth(valueKey.display, valueKey.screenNum)) { - d = RootWindow(valueKey.display, valueKey.screenNum); - } else { - d = Tk_GetPixmap(valueKey.display, - RootWindow(valueKey.display, valueKey.screenNum), - 1, 1, valueKey.depth); - freeDrawable = d; - } - - gcPtr->gc = XCreateGC(valueKey.display, d, valueMask, &valueKey.values); - gcPtr->display = valueKey.display; - gcPtr->refCount = 1; - gcPtr->valueHashPtr = valueHashPtr; - idKey.display = valueKey.display; - idKey.gc = gcPtr->gc; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); - if (!new) { - panic("GC already registered in Tk_GetGC"); - } - Tcl_SetHashValue(valueHashPtr, gcPtr); - Tcl_SetHashValue(idHashPtr, gcPtr); - if (freeDrawable != None) { - Tk_FreePixmap(valueKey.display, freeDrawable); - } - - return gcPtr->gc; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeGC -- - * - * This procedure is called to release a graphics context allocated by - * Tk_GetGC. - * - * Results: - * None. - * - * Side effects: - * The reference count associated with gc is decremented, and - * gc is officially deallocated if no-one is using it anymore. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeGC(display, gc) - Display *display; /* Display for which gc was allocated. */ - GC gc; /* Graphics context to be released. */ -{ - IdKey idKey; - Tcl_HashEntry *idHashPtr; - register TkGC *gcPtr; - - if (!initialized) { - panic("Tk_FreeGC called before Tk_GetGC"); - } - - idKey.display = display; - idKey.gc = gc; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); - if (idHashPtr == NULL) { - panic("Tk_FreeGC received unknown gc argument"); - } - gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr); - gcPtr->refCount--; - if (gcPtr->refCount == 0) { - Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc)); - XFreeGC(gcPtr->display, gcPtr->gc); - Tcl_DeleteHashEntry(gcPtr->valueHashPtr); - Tcl_DeleteHashEntry(idHashPtr); - ckfree((char *) gcPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * GCInit -- - * - * Initialize the structures used for GC management. - * - * Results: - * None. - * - * Side effects: - * Read the code. - * - *---------------------------------------------------------------------- - */ - -static void -GCInit() -{ - initialized = 1; - Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int)); - Tcl_InitHashTable(&idTable, sizeof(IdKey)/sizeof(int)); -} diff --git a/generic/tkGeometry.c b/generic/tkGeometry.c deleted file mode 100644 index 64f0b26..0000000 --- a/generic/tkGeometry.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * tkGeometry.c -- - * - * This file contains generic Tk code for geometry management - * (stuff that's used by all geometry managers). - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkGeometry.c,v 1.2 1998/09/14 18:23:11 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * Data structures of the following type are used by Tk_MaintainGeometry. - * For each slave managed by Tk_MaintainGeometry, there is one of these - * structures associated with its master. - */ - -typedef struct MaintainSlave { - Tk_Window slave; /* The slave window being positioned. */ - Tk_Window master; /* The master that determines slave's - * position; it must be a descendant of - * slave's parent. */ - int x, y; /* Desired position of slave relative to - * master. */ - int width, height; /* Desired dimensions of slave. */ - struct MaintainSlave *nextPtr; - /* Next in list of Maintains associated - * with master. */ -} MaintainSlave; - -/* - * For each window that has been specified as a master to - * Tk_MaintainGeometry, there is a structure of the following type: - */ - -typedef struct MaintainMaster { - Tk_Window ancestor; /* The lowest ancestor of this window - * for which we have *not* created a - * StructureNotify handler. May be the - * same as the window itself. */ - int checkScheduled; /* Non-zero means that there is already a - * call to MaintainCheckProc scheduled as - * an idle handler. */ - MaintainSlave *slavePtr; /* First in list of all slaves associated - * with this master. */ -} MaintainMaster; - -/* - * Hash table that maps from a master's Tk_Window token to a list of - * Maintains for that master: - */ - -static Tcl_HashTable maintainHashTable; - -/* - * Has maintainHashTable been initialized yet? - */ - -static int initialized = 0; - -/* - * Prototypes for static procedures in this file: - */ - -static void MaintainCheckProc _ANSI_ARGS_((ClientData clientData)); -static void MaintainMasterProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void MaintainSlaveProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_ManageGeometry -- - * - * Arrange for a particular procedure to manage the geometry - * of a given slave window. - * - * Results: - * None. - * - * Side effects: - * Proc becomes the new geometry manager for tkwin, replacing - * any previous geometry manager. The geometry manager will - * be notified (by calling procedures in *mgrPtr) when interesting - * things happen in the future. If there was an existing geometry - * manager for tkwin different from the new one, it is notified - * by calling its lostSlaveProc. - * - *-------------------------------------------------------------- - */ - -void -Tk_ManageGeometry(tkwin, mgrPtr, clientData) - Tk_Window tkwin; /* Window whose geometry is to - * be managed by proc. */ - Tk_GeomMgr *mgrPtr; /* Static structure describing the - * geometry manager. This structure - * must never go away. */ - ClientData clientData; /* Arbitrary one-word argument to - * pass to geometry manager procedures. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if ((winPtr->geomMgrPtr != NULL) && (mgrPtr != NULL) - && ((winPtr->geomMgrPtr != mgrPtr) - || (winPtr->geomData != clientData)) - && (winPtr->geomMgrPtr->lostSlaveProc != NULL)) { - (*winPtr->geomMgrPtr->lostSlaveProc)(winPtr->geomData, tkwin); - } - - winPtr->geomMgrPtr = mgrPtr; - winPtr->geomData = clientData; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GeometryRequest -- - * - * This procedure is invoked by widget code to indicate - * its preferences about the size of a window it manages. - * In general, widget code should call this procedure - * rather than Tk_ResizeWindow. - * - * Results: - * None. - * - * Side effects: - * The geometry manager for tkwin (if any) is invoked to - * handle the request. If possible, it will reconfigure - * tkwin and/or other windows to satisfy the request. The - * caller gets no indication of success or failure, but it - * will get X events if the window size was actually - * changed. - * - *-------------------------------------------------------------- - */ - -void -Tk_GeometryRequest(tkwin, reqWidth, reqHeight) - Tk_Window tkwin; /* Window that geometry information - * pertains to. */ - int reqWidth, reqHeight; /* Minimum desired dimensions for - * window, in pixels. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - /* - * X gets very upset if a window requests a width or height of - * zero, so rounds requested sizes up to at least 1. - */ - - if (reqWidth <= 0) { - reqWidth = 1; - } - if (reqHeight <= 0) { - reqHeight = 1; - } - if ((reqWidth == winPtr->reqWidth) && (reqHeight == winPtr->reqHeight)) { - return; - } - winPtr->reqWidth = reqWidth; - winPtr->reqHeight = reqHeight; - if ((winPtr->geomMgrPtr != NULL) - && (winPtr->geomMgrPtr->requestProc != NULL)) { - (*winPtr->geomMgrPtr->requestProc)(winPtr->geomData, tkwin); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SetInternalBorder -- - * - * Notify relevant geometry managers that a window has an internal - * border of a given width and that child windows should not be - * placed on that border. - * - * Results: - * None. - * - * Side effects: - * The border width is recorded for the window, and all geometry - * managers of all children are notified so that can re-layout, if - * necessary. - * - *---------------------------------------------------------------------- - */ - -void -Tk_SetInternalBorder(tkwin, width) - Tk_Window tkwin; /* Window that will have internal border. */ - int width; /* Width of internal border, in pixels. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if (width == winPtr->internalBorderWidth) { - return; - } - if (width < 0) { - width = 0; - } - winPtr->internalBorderWidth = width; - - /* - * All the slaves for which this is the master window must now be - * repositioned to take account of the new internal border width. - * To signal all the geometry managers to do this, just resize the - * window to its current size. The ConfigureNotify event will - * cause geometry managers to recompute everything. - */ - - Tk_ResizeWindow(tkwin, Tk_Width(tkwin), Tk_Height(tkwin)); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_MaintainGeometry -- - * - * This procedure is invoked by geometry managers to handle slaves - * whose master's are not their parents. It translates the desired - * geometry for the slave into the coordinate system of the parent - * and respositions the slave if it isn't already at the right place. - * Furthermore, it sets up event handlers so that if the master (or - * any of its ancestors up to the slave's parent) is mapped, unmapped, - * or moved, then the slave will be adjusted to match. - * - * Results: - * None. - * - * Side effects: - * Event handlers are created and state is allocated to keep track - * of slave. Note: if slave was already managed for master by - * Tk_MaintainGeometry, then the previous information is replaced - * with the new information. The caller must eventually call - * Tk_UnmaintainGeometry to eliminate the correspondence (or, the - * state is automatically freed when either window is destroyed). - * - *---------------------------------------------------------------------- - */ - -void -Tk_MaintainGeometry(slave, master, x, y, width, height) - Tk_Window slave; /* Slave for geometry management. */ - Tk_Window master; /* Master for slave; must be a descendant - * of slave's parent. */ - int x, y; /* Desired position of slave within master. */ - int width, height; /* Desired dimensions for slave. */ -{ - Tcl_HashEntry *hPtr; - MaintainMaster *masterPtr; - register MaintainSlave *slavePtr; - int new, map; - Tk_Window ancestor, parent; - - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS); - } - - /* - * See if there is already a MaintainMaster structure for the master; - * if not, then create one. - */ - - parent = Tk_Parent(slave); - hPtr = Tcl_CreateHashEntry(&maintainHashTable, (char *) master, &new); - if (!new) { - masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr); - } else { - masterPtr = (MaintainMaster *) ckalloc(sizeof(MaintainMaster)); - masterPtr->ancestor = master; - masterPtr->checkScheduled = 0; - masterPtr->slavePtr = NULL; - Tcl_SetHashValue(hPtr, masterPtr); - } - - /* - * Create a MaintainSlave structure for the slave if there isn't - * already one. - */ - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - if (slavePtr->slave == slave) { - goto gotSlave; - } - } - slavePtr = (MaintainSlave *) ckalloc(sizeof(MaintainSlave)); - slavePtr->slave = slave; - slavePtr->master = master; - slavePtr->nextPtr = masterPtr->slavePtr; - masterPtr->slavePtr = slavePtr; - Tk_CreateEventHandler(slave, StructureNotifyMask, MaintainSlaveProc, - (ClientData) slavePtr); - - /* - * Make sure that there are event handlers registered for all - * the windows between master and slave's parent (including master - * but not slave's parent). There may already be handlers for master - * and some of its ancestors (masterPtr->ancestor tells how many). - */ - - for (ancestor = master; ancestor != parent; - ancestor = Tk_Parent(ancestor)) { - if (ancestor == masterPtr->ancestor) { - Tk_CreateEventHandler(ancestor, StructureNotifyMask, - MaintainMasterProc, (ClientData) masterPtr); - masterPtr->ancestor = Tk_Parent(ancestor); - } - } - - /* - * Fill in up-to-date information in the structure, then update the - * window if it's not currently in the right place or state. - */ - - gotSlave: - slavePtr->x = x; - slavePtr->y = y; - slavePtr->width = width; - slavePtr->height = height; - map = 1; - for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) { - if (!Tk_IsMapped(ancestor) && (ancestor != parent)) { - map = 0; - } - if (ancestor == parent) { - if ((x != Tk_X(slavePtr->slave)) - || (y != Tk_Y(slavePtr->slave)) - || (width != Tk_Width(slavePtr->slave)) - || (height != Tk_Height(slavePtr->slave))) { - Tk_MoveResizeWindow(slavePtr->slave, x, y, width, height); - } - if (map) { - Tk_MapWindow(slavePtr->slave); - } else { - Tk_UnmapWindow(slavePtr->slave); - } - break; - } - x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width; - y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_UnmaintainGeometry -- - * - * This procedure cancels a previous Tk_MaintainGeometry call, - * so that the relationship between slave and master is no longer - * maintained. - * - * Results: - * None. - * - * Side effects: - * The slave is unmapped and state is released, so that slave won't - * track master any more. If we weren't previously managing slave - * relative to master, then this procedure has no effect. - * - *---------------------------------------------------------------------- - */ - -void -Tk_UnmaintainGeometry(slave, master) - Tk_Window slave; /* Slave for geometry management. */ - Tk_Window master; /* Master for slave; must be a descendant - * of slave's parent. */ -{ - Tcl_HashEntry *hPtr; - MaintainMaster *masterPtr; - register MaintainSlave *slavePtr, *prevPtr; - Tk_Window ancestor; - - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS); - } - - if (!(((TkWindow *) slave)->flags & TK_ALREADY_DEAD)) { - Tk_UnmapWindow(slave); - } - hPtr = Tcl_FindHashEntry(&maintainHashTable, (char *) master); - if (hPtr == NULL) { - return; - } - masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr); - slavePtr = masterPtr->slavePtr; - if (slavePtr->slave == slave) { - masterPtr->slavePtr = slavePtr->nextPtr; - } else { - for (prevPtr = slavePtr, slavePtr = slavePtr->nextPtr; ; - prevPtr = slavePtr, slavePtr = slavePtr->nextPtr) { - if (slavePtr == NULL) { - return; - } - if (slavePtr->slave == slave) { - prevPtr->nextPtr = slavePtr->nextPtr; - break; - } - } - } - Tk_DeleteEventHandler(slavePtr->slave, StructureNotifyMask, - MaintainSlaveProc, (ClientData) slavePtr); - ckfree((char *) slavePtr); - if (masterPtr->slavePtr == NULL) { - if (masterPtr->ancestor != NULL) { - for (ancestor = master; ; ancestor = Tk_Parent(ancestor)) { - Tk_DeleteEventHandler(ancestor, StructureNotifyMask, - MaintainMasterProc, (ClientData) masterPtr); - if (ancestor == masterPtr->ancestor) { - break; - } - } - } - if (masterPtr->checkScheduled) { - Tcl_CancelIdleCall(MaintainCheckProc, (ClientData) masterPtr); - } - Tcl_DeleteHashEntry(hPtr); - ckfree((char *) masterPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * MaintainMasterProc -- - * - * This procedure is invoked by the Tk event dispatcher in - * response to StructureNotify events on the master or one - * of its ancestors, on behalf of Tk_MaintainGeometry. - * - * Results: - * None. - * - * Side effects: - * It schedules a call to MaintainCheckProc, which will eventually - * caused the postions and mapped states to be recalculated for all - * the maintained slaves of the master. Or, if the master window is - * being deleted then state is cleaned up. - * - *---------------------------------------------------------------------- - */ - -static void -MaintainMasterProc(clientData, eventPtr) - ClientData clientData; /* Pointer to MaintainMaster structure - * for the master window. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - MaintainMaster *masterPtr = (MaintainMaster *) clientData; - MaintainSlave *slavePtr; - int done; - - if ((eventPtr->type == ConfigureNotify) - || (eventPtr->type == MapNotify) - || (eventPtr->type == UnmapNotify)) { - if (!masterPtr->checkScheduled) { - masterPtr->checkScheduled = 1; - Tcl_DoWhenIdle(MaintainCheckProc, (ClientData) masterPtr); - } - } else if (eventPtr->type == DestroyNotify) { - /* - * Delete all of the state associated with this master, but - * be careful not to use masterPtr after the last slave is - * deleted, since its memory will have been freed. - */ - - done = 0; - do { - slavePtr = masterPtr->slavePtr; - if (slavePtr->nextPtr == NULL) { - done = 1; - } - Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master); - } while (!done); - } -} - -/* - *---------------------------------------------------------------------- - * - * MaintainSlaveProc -- - * - * This procedure is invoked by the Tk event dispatcher in - * response to StructureNotify events on a slave being managed - * by Tk_MaintainGeometry. - * - * Results: - * None. - * - * Side effects: - * If the event is a DestroyNotify event then the Maintain state - * and event handlers for this slave are deleted. - * - *---------------------------------------------------------------------- - */ - -static void -MaintainSlaveProc(clientData, eventPtr) - ClientData clientData; /* Pointer to MaintainSlave structure - * for master-slave pair. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - MaintainSlave *slavePtr = (MaintainSlave *) clientData; - - if (eventPtr->type == DestroyNotify) { - Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master); - } -} - -/* - *---------------------------------------------------------------------- - * - * MaintainCheckProc -- - * - * This procedure is invoked by the Tk event dispatcher as an - * idle handler, when a master or one of its ancestors has been - * reconfigured, mapped, or unmapped. Its job is to scan all of - * the slaves for the master and reposition them, map them, or - * unmap them as needed to maintain their geometry relative to - * the master. - * - * Results: - * None. - * - * Side effects: - * Slaves can get repositioned, mapped, or unmapped. - * - *---------------------------------------------------------------------- - */ - -static void -MaintainCheckProc(clientData) - ClientData clientData; /* Pointer to MaintainMaster structure - * for the master window. */ -{ - MaintainMaster *masterPtr = (MaintainMaster *) clientData; - MaintainSlave *slavePtr; - Tk_Window ancestor, parent; - int x, y, map; - - masterPtr->checkScheduled = 0; - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - parent = Tk_Parent(slavePtr->slave); - x = slavePtr->x; - y = slavePtr->y; - map = 1; - for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) { - if (!Tk_IsMapped(ancestor) && (ancestor != parent)) { - map = 0; - } - if (ancestor == parent) { - if ((x != Tk_X(slavePtr->slave)) - || (y != Tk_Y(slavePtr->slave))) { - Tk_MoveWindow(slavePtr->slave, x, y); - } - if (map) { - Tk_MapWindow(slavePtr->slave); - } else { - Tk_UnmapWindow(slavePtr->slave); - } - break; - } - x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width; - y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width; - } - } -} diff --git a/generic/tkGet.c b/generic/tkGet.c deleted file mode 100644 index 3507e9b..0000000 --- a/generic/tkGet.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * tkGet.c -- - * - * This file contains a number of "Tk_GetXXX" procedures, which - * parse text strings into useful forms for Tk. This file has - * the simpler procedures, like Tk_GetDirection and Tk_GetUid. - * The more complex procedures like Tk_GetColor are in separate - * files. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkGet.c,v 1.2 1998/09/14 18:23:11 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - * The hash table below is used to keep track of all the Tk_Uids created - * so far. - */ - -static Tcl_HashTable uidTable; -static int initialized = 0; - -/* - *-------------------------------------------------------------- - * - * Tk_GetAnchor -- - * - * Given a string, return the corresponding Tk_Anchor. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * position is stored at *anchorPtr; otherwise TCL_ERROR - * is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetAnchor(interp, string, anchorPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - char *string; /* String describing a direction. */ - Tk_Anchor *anchorPtr; /* Where to store Tk_Anchor corresponding - * to string. */ -{ - switch (string[0]) { - case 'n': - if (string[1] == 0) { - *anchorPtr = TK_ANCHOR_N; - return TCL_OK; - } else if ((string[1] == 'e') && (string[2] == 0)) { - *anchorPtr = TK_ANCHOR_NE; - return TCL_OK; - } else if ((string[1] == 'w') && (string[2] == 0)) { - *anchorPtr = TK_ANCHOR_NW; - return TCL_OK; - } - goto error; - case 's': - if (string[1] == 0) { - *anchorPtr = TK_ANCHOR_S; - return TCL_OK; - } else if ((string[1] == 'e') && (string[2] == 0)) { - *anchorPtr = TK_ANCHOR_SE; - return TCL_OK; - } else if ((string[1] == 'w') && (string[2] == 0)) { - *anchorPtr = TK_ANCHOR_SW; - return TCL_OK; - } else { - goto error; - } - case 'e': - if (string[1] == 0) { - *anchorPtr = TK_ANCHOR_E; - return TCL_OK; - } - goto error; - case 'w': - if (string[1] == 0) { - *anchorPtr = TK_ANCHOR_W; - return TCL_OK; - } - goto error; - case 'c': - if (strncmp(string, "center", strlen(string)) == 0) { - *anchorPtr = TK_ANCHOR_CENTER; - return TCL_OK; - } - goto error; - } - - error: - Tcl_AppendResult(interp, "bad anchor position \"", string, - "\": must be n, ne, e, se, s, sw, w, nw, or center", - (char *) NULL); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfAnchor -- - * - * Given a Tk_Anchor, return the string that corresponds - * to it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfAnchor(anchor) - Tk_Anchor anchor; /* Anchor for which identifying string - * is desired. */ -{ - switch (anchor) { - case TK_ANCHOR_N: return "n"; - case TK_ANCHOR_NE: return "ne"; - case TK_ANCHOR_E: return "e"; - case TK_ANCHOR_SE: return "se"; - case TK_ANCHOR_S: return "s"; - case TK_ANCHOR_SW: return "sw"; - case TK_ANCHOR_W: return "w"; - case TK_ANCHOR_NW: return "nw"; - case TK_ANCHOR_CENTER: return "center"; - } - return "unknown anchor position"; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetJoinStyle -- - * - * Given a string, return the corresponding Tk_JoinStyle. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * justification is stored at *joinPtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetJoinStyle(interp, string, joinPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - char *string; /* String describing a justification style. */ - int *joinPtr; /* Where to store join style corresponding - * to string. */ -{ - int c; - size_t length; - - c = string[0]; - length = strlen(string); - - if ((c == 'b') && (strncmp(string, "bevel", length) == 0)) { - *joinPtr = JoinBevel; - return TCL_OK; - } - if ((c == 'm') && (strncmp(string, "miter", length) == 0)) { - *joinPtr = JoinMiter; - return TCL_OK; - } - if ((c == 'r') && (strncmp(string, "round", length) == 0)) { - *joinPtr = JoinRound; - return TCL_OK; - } - - Tcl_AppendResult(interp, "bad join style \"", string, - "\": must be bevel, miter, or round", - (char *) NULL); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfJoinStyle -- - * - * Given a Tk_JoinStyle, return the string that corresponds - * to it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfJoinStyle(join) - int join; /* Join style for which identifying string - * is desired. */ -{ - switch (join) { - case JoinBevel: return "bevel"; - case JoinMiter: return "miter"; - case JoinRound: return "round"; - } - return "unknown join style"; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetCapStyle -- - * - * Given a string, return the corresponding Tk_CapStyle. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * justification is stored at *capPtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetCapStyle(interp, string, capPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - char *string; /* String describing a justification style. */ - int *capPtr; /* Where to store cap style corresponding - * to string. */ -{ - int c; - size_t length; - - c = string[0]; - length = strlen(string); - - if ((c == 'b') && (strncmp(string, "butt", length) == 0)) { - *capPtr = CapButt; - return TCL_OK; - } - if ((c == 'p') && (strncmp(string, "projecting", length) == 0)) { - *capPtr = CapProjecting; - return TCL_OK; - } - if ((c == 'r') && (strncmp(string, "round", length) == 0)) { - *capPtr = CapRound; - return TCL_OK; - } - - Tcl_AppendResult(interp, "bad cap style \"", string, - "\": must be butt, projecting, or round", - (char *) NULL); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfCapStyle -- - * - * Given a Tk_CapStyle, return the string that corresponds - * to it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfCapStyle(cap) - int cap; /* Cap style for which identifying string - * is desired. */ -{ - switch (cap) { - case CapButt: return "butt"; - case CapProjecting: return "projecting"; - case CapRound: return "round"; - } - return "unknown cap style"; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetJustify -- - * - * Given a string, return the corresponding Tk_Justify. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * justification is stored at *justifyPtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetJustify(interp, string, justifyPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - char *string; /* String describing a justification style. */ - Tk_Justify *justifyPtr; /* Where to store Tk_Justify corresponding - * to string. */ -{ - int c; - size_t length; - - c = string[0]; - length = strlen(string); - - if ((c == 'l') && (strncmp(string, "left", length) == 0)) { - *justifyPtr = TK_JUSTIFY_LEFT; - return TCL_OK; - } - if ((c == 'r') && (strncmp(string, "right", length) == 0)) { - *justifyPtr = TK_JUSTIFY_RIGHT; - return TCL_OK; - } - if ((c == 'c') && (strncmp(string, "center", length) == 0)) { - *justifyPtr = TK_JUSTIFY_CENTER; - return TCL_OK; - } - - Tcl_AppendResult(interp, "bad justification \"", string, - "\": must be left, right, or center", - (char *) NULL); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * Tk_NameOfJustify -- - * - * Given a Tk_Justify, return the string that corresponds - * to it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -char * -Tk_NameOfJustify(justify) - Tk_Justify justify; /* Justification style for which - * identifying string is desired. */ -{ - switch (justify) { - case TK_JUSTIFY_LEFT: return "left"; - case TK_JUSTIFY_RIGHT: return "right"; - case TK_JUSTIFY_CENTER: return "center"; - } - return "unknown justification style"; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetUid -- - * - * Given a string, this procedure returns a unique identifier - * for the string. - * - * Results: - * This procedure returns a Tk_Uid corresponding to the "string" - * argument. The Tk_Uid has a string value identical to string - * (strcmp will return 0), but it's guaranteed that any other - * calls to this procedure with a string equal to "string" will - * return exactly the same result (i.e. can compare Tk_Uid - * *values* directly, without having to call strcmp on what they - * point to). - * - * Side effects: - * New information may be entered into the identifier table. - * - *---------------------------------------------------------------------- - */ - -Tk_Uid -Tk_GetUid(string) - CONST char *string; /* String to convert. */ -{ - int dummy; - - if (!initialized) { - Tcl_InitHashTable(&uidTable, TCL_STRING_KEYS); - initialized = 1; - } - return (Tk_Uid) Tcl_GetHashKey(&uidTable, - Tcl_CreateHashEntry(&uidTable, string, &dummy)); -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetScreenMM -- - * - * Given a string, returns the number of screen millimeters - * corresponding to that string. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * screen distance is stored at *doublePtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetScreenMM(interp, tkwin, string, doublePtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - Tk_Window tkwin; /* Window whose screen determines conversion - * from centimeters and other absolute - * units. */ - char *string; /* String describing a screen distance. */ - double *doublePtr; /* Place to store converted result. */ -{ - char *end; - double d; - - d = strtod(string, &end); - if (end == string) { - error: - Tcl_AppendResult(interp, "bad screen distance \"", string, - "\"", (char *) NULL); - return TCL_ERROR; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - switch (*end) { - case 0: - d /= WidthOfScreen(Tk_Screen(tkwin)); - d *= WidthMMOfScreen(Tk_Screen(tkwin)); - break; - case 'c': - d *= 10; - end++; - break; - case 'i': - d *= 25.4; - end++; - break; - case 'm': - end++; - break; - case 'p': - d *= 25.4/72.0; - end++; - break; - default: - goto error; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - if (*end != 0) { - goto error; - } - *doublePtr = d; - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetPixels -- - * - * Given a string, returns the number of pixels corresponding - * to that string. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the - * rounded pixel distance is stored at *intPtr; otherwise - * TCL_ERROR is returned and an error message is left in - * interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetPixels(interp, tkwin, string, intPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - Tk_Window tkwin; /* Window whose screen determines conversion - * from centimeters and other absolute - * units. */ - char *string; /* String describing a justification style. */ - int *intPtr; /* Place to store converted result. */ -{ - char *end; - double d; - - d = strtod(string, &end); - if (end == string) { - error: - Tcl_AppendResult(interp, "bad screen distance \"", string, - "\"", (char *) NULL); - return TCL_ERROR; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - switch (*end) { - case 0: - break; - case 'c': - d *= 10*WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - end++; - break; - case 'i': - d *= 25.4*WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - end++; - break; - case 'm': - d *= WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - end++; - break; - case 'p': - d *= (25.4/72.0)*WidthOfScreen(Tk_Screen(tkwin)); - d /= WidthMMOfScreen(Tk_Screen(tkwin)); - end++; - break; - default: - goto error; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { - end++; - } - if (*end != 0) { - goto error; - } - if (d < 0) { - *intPtr = (int) (d - 0.5); - } else { - *intPtr = (int) (d + 0.5); - } - return TCL_OK; -} diff --git a/generic/tkGrab.c b/generic/tkGrab.c deleted file mode 100644 index bbb4f65..0000000 --- a/generic/tkGrab.c +++ /dev/null @@ -1,1535 +0,0 @@ -/* - * tkGrab.c -- - * - * This file provides procedures that implement grabs for Tk. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkGrab.c,v 1.2 1998/09/14 18:23:11 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * The grab state machine has four states: ungrabbed, button pressed, - * grabbed, and button pressed while grabbed. In addition, there are - * three pieces of grab state information: the current grab window, - * the current restrict window, and whether the mouse is captured. - * - * The current grab window specifies the point in the Tk window - * heirarchy above which pointer events will not be reported. Any - * window within the subtree below the grab window will continue to - * receive events as normal. Events outside of the grab tree will be - * reported to the grab window. - * - * If the current restrict window is set, then all pointer events will - * be reported only to the restrict window. The restrict window is - * normally set during an automatic button grab. - * - * The mouse capture state specifies whether the window system will - * report mouse events outside of any Tk toplevels. This is set - * during a global grab or an automatic button grab. - * - * The transitions between different states is given in the following - * table: - * - * Event\State U B G GB - * ----------- -- -- -- -- - * FirstPress B B GB GB - * Press B B G GB - * Release U B G GB - * LastRelease U U G G - * Grab G G G G - * Ungrab U B U U - * - * Note: U=Ungrabbed, B=Button, G=Grabbed, GB=Grab and Button - * - * In addition, the following conditions are always true: - * - * State\Variable Grab Restrict Capture - * -------------- ---- -------- ------- - * Ungrabbed 0 0 0 - * Button 0 1 1 - * Grabbed 1 0 b/g - * Grab and Button 1 1 1 - * - * Note: 0 means variable is set to NULL, 1 means variable is set to - * some window, b/g means the variable is set to a window if a button - * is currently down or a global grab is in effect. - * - * The final complication to all of this is enter and leave events. - * In order to correctly handle all of the various cases, Tk cannot - * rely on X enter/leave events in all situations. The following - * describes the correct sequence of enter and leave events that - * should be observed by Tk scripts: - * - * Event(state) Enter/Leave From -> To - * ------------ ---------------------- - * LastRelease(B | GB): restrict window -> anc(grab window, event window) - * Grab(U | B): event window -> anc(grab window, event window) - * Grab(G): anc(old grab window, event window) -> - * anc(new grab window, event window) - * Grab(GB): restrict window -> anc(new grab window, event window) - * Ungrab(G): anc(grab window, event window) -> event window - * Ungrab(GB): restrict window -> event window - * - * Note: anc(x,y) returns the least ancestor of y that is in the tree - * of x, terminating at toplevels. - */ - -/* - * The following structure is used to pass information to - * GrabRestrictProc from EatGrabEvents. - */ - -typedef struct { - Display *display; /* Display from which to discard events. */ - unsigned int serial; /* Serial number with which to compare. */ -} GrabInfo; - -/* - * Bit definitions for grabFlags field of TkDisplay structures: - * - * GRAB_GLOBAL 1 means this is a global grab (we grabbed via - * the server so all applications are locked out). - * 0 means this is a local grab that affects - * only this application. - * GRAB_TEMP_GLOBAL 1 means we've temporarily grabbed via the - * server because a button is down and we want - * to make sure that we get the button-up - * event. The grab will be released when the - * last mouse button goes up. - */ - -#define GRAB_GLOBAL 1 -#define GRAB_TEMP_GLOBAL 4 - -/* - * The following structure is a Tcl_Event that triggers a change in - * the grabWinPtr field of a display. This event guarantees that - * the change occurs in the proper order relative to enter and leave - * events. - */ - -typedef struct NewGrabWinEvent { - Tcl_Event header; /* Standard information for all Tcl events. */ - TkDisplay *dispPtr; /* Display whose grab window is to change. */ - Window grabWindow; /* New grab window for display. This is - * recorded instead of a (TkWindow *) because - * it will allow us to detect cases where - * the window is destroyed before this event - * is processed. */ -} NewGrabWinEvent; - -/* - * The following magic value is stored in the "send_event" field of - * EnterNotify and LeaveNotify events that are generated in this - * file. This allows us to separate "real" events coming from the - * server from those that we generated. - */ - -#define GENERATED_EVENT_MAGIC ((Bool) 0x147321ac) - -/* - * Mask that selects any of the state bits corresponding to buttons, - * plus masks that select individual buttons' bits: - */ - -#define ALL_BUTTONS \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) -static unsigned int buttonStates[] = { - Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask -}; - -/* - * Forward declarations for procedures declared later in this file: - */ - -static void EatGrabEvents _ANSI_ARGS_((TkDisplay *dispPtr, - unsigned int serial)); -static TkWindow * FindCommonAncestor _ANSI_ARGS_((TkWindow *winPtr1, - TkWindow *winPtr2, int *countPtr1, - int *countPtr2)); -static Tk_RestrictAction GrabRestrictProc _ANSI_ARGS_((ClientData arg, - XEvent *eventPtr)); -static int GrabWinEventProc _ANSI_ARGS_((Tcl_Event *evPtr, - int flags)); -static void MovePointer2 _ANSI_ARGS_((TkWindow *sourcePtr, - TkWindow *destPtr, int mode, int leaveEvents, - int EnterEvents)); -static void QueueGrabWindowChange _ANSI_ARGS_((TkDisplay *dispPtr, - TkWindow *grabWinPtr)); -static void ReleaseButtonGrab _ANSI_ARGS_((TkDisplay *dispPtr)); - -/* - *---------------------------------------------------------------------- - * - * Tk_GrabCmd -- - * - * This procedure is invoked to process the "grab" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tk_GrabCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - int globalGrab, c; - Tk_Window tkwin; - TkDisplay *dispPtr; - size_t length; - - if (argc < 2) { - badArgs: - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ?-global? window\" or \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if (c == '.') { - if (argc != 2) { - goto badArgs; - } - tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData); - if (tkwin == NULL) { - return TCL_ERROR; - } - return Tk_Grab(interp, tkwin, 0); - } else if ((c == '-') && (strncmp(argv[1], "-global", length) == 0) - && (length >= 2)) { - if (argc != 3) { - goto badArgs; - } - tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); - if (tkwin == NULL) { - return TCL_ERROR; - } - return Tk_Grab(interp, tkwin, 1); - } else if ((c == 'c') && (strncmp(argv[1], "current", length) == 0)) { - if (argc > 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " current ?window?\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 3) { - tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); - if (tkwin == NULL) { - return TCL_ERROR; - } - dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (dispPtr->eventualGrabWinPtr != NULL) { - interp->result = dispPtr->eventualGrabWinPtr->pathName; - } - } else { - for (dispPtr = tkDisplayList; dispPtr != NULL; - dispPtr = dispPtr->nextPtr) { - if (dispPtr->eventualGrabWinPtr != NULL) { - Tcl_AppendElement(interp, - dispPtr->eventualGrabWinPtr->pathName); - } - } - } - return TCL_OK; - } else if ((c == 'r') && (strncmp(argv[1], "release", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " release window\"", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); - if (tkwin == NULL) { - Tcl_ResetResult(interp); - } else { - Tk_Ungrab(tkwin); - } - } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0) - && (length >= 2)) { - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " set ?-global? window\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 3) { - globalGrab = 0; - tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); - } else { - globalGrab = 1; - length = strlen(argv[2]); - if ((strncmp(argv[2], "-global", length) != 0) || (length < 2)) { - Tcl_AppendResult(interp, "bad argument \"", argv[2], - "\": must be \"", argv[0], " set ?-global? window\"", - (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_NameToWindow(interp, argv[3], (Tk_Window) clientData); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - return Tk_Grab(interp, tkwin, globalGrab); - } else if ((c == 's') && (strncmp(argv[1], "status", length) == 0) - && (length >= 2)) { - TkWindow *winPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " status window\"", (char *) NULL); - return TCL_ERROR; - } - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], - (Tk_Window) clientData); - if (winPtr == NULL) { - return TCL_ERROR; - } - dispPtr = winPtr->dispPtr; - if (dispPtr->eventualGrabWinPtr != winPtr) { - interp->result = "none"; - } else if (dispPtr->grabFlags & GRAB_GLOBAL) { - interp->result = "global"; - } else { - interp->result = "local"; - } - } else { - Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], - "\": must be current, release, set, or status", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_Grab -- - * - * Grabs the pointer and keyboard, so that mouse-related events are - * only reported relative to a given window and its descendants. - * - * Results: - * A standard Tcl result is returned. TCL_OK is the normal return - * value; if the grab could not be set then TCL_ERROR is returned - * and interp->result will hold an error message. - * - * Side effects: - * Once this call completes successfully, no window outside the - * tree rooted at tkwin will receive pointer- or keyboard-related - * events until the next call to Tk_Ungrab. If a previous grab was - * in effect within this application, then it is replaced with a new - * one. - * - *---------------------------------------------------------------------- - */ - -int -Tk_Grab(interp, tkwin, grabGlobal) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Window tkwin; /* Window on whose behalf the pointer - * is to be grabbed. */ - int grabGlobal; /* Non-zero means issue a grab to the - * server so that no other application - * gets mouse or keyboard events. - * Zero means the grab only applies - * within this application. */ -{ - int grabResult, numTries; - TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkWindow *winPtr2; - unsigned int serial; - - ReleaseButtonGrab(dispPtr); - if (dispPtr->eventualGrabWinPtr != NULL) { - if ((dispPtr->eventualGrabWinPtr == winPtr) - && (grabGlobal == ((dispPtr->grabFlags & GRAB_GLOBAL) != 0))) { - return TCL_OK; - } - if (dispPtr->eventualGrabWinPtr->mainPtr != winPtr->mainPtr) { - alreadyGrabbed: - interp->result = "grab failed: another application has grab"; - return TCL_ERROR; - } - Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr); - } - - Tk_MakeWindowExist(tkwin); - if (!grabGlobal) { - Window dummy1, dummy2; - int dummy3, dummy4, dummy5, dummy6; - unsigned int state; - - /* - * Local grab. However, if any mouse buttons are down, turn - * it into a global grab temporarily, until the last button - * goes up. This does two things: (a) it makes sure that we - * see the button-up event; and (b) it allows us to track mouse - * motion among all of the windows of this application. - */ - - dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL); - XQueryPointer(dispPtr->display, winPtr->window, &dummy1, - &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &state); - if ((state & ALL_BUTTONS) != 0) { - dispPtr->grabFlags |= GRAB_TEMP_GLOBAL; - goto setGlobalGrab; - } - } else { - dispPtr->grabFlags |= GRAB_GLOBAL; - setGlobalGrab: - - /* - * Tricky point: must ungrab before grabbing. This is needed - * in case there is a button auto-grab already in effect. If - * there is, and the mouse has moved to a different window, X - * won't generate enter and leave events to move the mouse if - * we grab without ungrabbing. - */ - - XUngrabPointer(dispPtr->display, CurrentTime); - serial = NextRequest(dispPtr->display); - - /* - * Another tricky point: there are races with some window - * managers that can cause grabs to fail because the window - * manager hasn't released its grab quickly enough. To work - * around this problem, retry a few times after AlreadyGrabbed - * errors to give the grab release enough time to register with - * the server. - */ - - grabResult = 0; /* Needed only to prevent gcc - * compiler warnings. */ - for (numTries = 0; numTries < 10; numTries++) { - grabResult = XGrabPointer(dispPtr->display, winPtr->window, - True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask - |PointerMotionMask, GrabModeAsync, GrabModeAsync, None, - None, CurrentTime); - if (grabResult != AlreadyGrabbed) { - break; - } - Tcl_Sleep(100); - } - if (grabResult != 0) { - grabError: - if (grabResult == GrabNotViewable) { - interp->result = "grab failed: window not viewable"; - } else if (grabResult == AlreadyGrabbed) { - goto alreadyGrabbed; - } else if (grabResult == GrabFrozen) { - interp->result = "grab failed: keyboard or pointer frozen"; - } else if (grabResult == GrabInvalidTime) { - interp->result = "grab failed: invalid time"; - } else { - char msg[100]; - - sprintf(msg, "grab failed for unknown reason (code %d)", - grabResult); - Tcl_AppendResult(interp, msg, (char *) NULL); - } - return TCL_ERROR; - } - grabResult = XGrabKeyboard(dispPtr->display, Tk_WindowId(tkwin), - False, GrabModeAsync, GrabModeAsync, CurrentTime); - if (grabResult != 0) { - XUngrabPointer(dispPtr->display, CurrentTime); - goto grabError; - } - - /* - * Eat up any grab-related events generated by the server for the - * grab. There are several reasons for doing this: - * - * 1. We have to synthesize the events for local grabs anyway, since - * the server doesn't participate in them. - * 2. The server doesn't always generate the right events for global - * grabs (e.g. it generates events even if the current window is - * in the grab tree, which we don't want). - * 3. We want all the grab-related events to be processed immediately - * (before other events that are already queued); events coming - * from the server will be in the wrong place, but events we - * synthesize here will go to the front of the queue. - */ - - EatGrabEvents(dispPtr, serial); - } - - /* - * Synthesize leave events to move the pointer from its current window - * up to the lowest ancestor that it has in common with the grab window. - * However, only do this if the pointer is outside the grab window's - * subtree but inside the grab window's application. - */ - - if ((dispPtr->serverWinPtr != NULL) - && (dispPtr->serverWinPtr->mainPtr == winPtr->mainPtr)) { - for (winPtr2 = dispPtr->serverWinPtr; ; winPtr2 = winPtr2->parentPtr) { - if (winPtr2 == winPtr) { - break; - } - if (winPtr2 == NULL) { - MovePointer2(dispPtr->serverWinPtr, winPtr, NotifyGrab, 1, 0); - break; - } - } - } - QueueGrabWindowChange(dispPtr, winPtr); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_Ungrab -- - * - * Releases a grab on the mouse pointer and keyboard, if there - * is one set on the specified window. - * - * Results: - * None. - * - * Side effects: - * Pointer and keyboard events will start being delivered to other - * windows again. - * - *---------------------------------------------------------------------- - */ - -void -Tk_Ungrab(tkwin) - Tk_Window tkwin; /* Window whose grab should be - * released. */ -{ - TkDisplay *dispPtr; - TkWindow *grabWinPtr, *winPtr; - unsigned int serial; - - grabWinPtr = (TkWindow *) tkwin; - dispPtr = grabWinPtr->dispPtr; - if (grabWinPtr != dispPtr->eventualGrabWinPtr) { - return; - } - ReleaseButtonGrab(dispPtr); - QueueGrabWindowChange(dispPtr, (TkWindow *) NULL); - if (dispPtr->grabFlags & (GRAB_GLOBAL|GRAB_TEMP_GLOBAL)) { - dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL); - serial = NextRequest(dispPtr->display); - XUngrabPointer(dispPtr->display, CurrentTime); - XUngrabKeyboard(dispPtr->display, CurrentTime); - EatGrabEvents(dispPtr, serial); - } - - /* - * Generate events to move the pointer back to the window where it - * really is. Some notes: - * 1. As with grabs, only do this if the "real" window is not a - * descendant of the grab window, since in this case the pointer - * is already where it's supposed to be. - * 2. If the "real" window is in some other application then don't - * generate any events at all, since everything's already been - * reported correctly. - * 3. Only generate enter events. Don't generate leave events, - * because we never told the lower-level windows that they - * had the pointer in the first place. - */ - - for (winPtr = dispPtr->serverWinPtr; ; winPtr = winPtr->parentPtr) { - if (winPtr == grabWinPtr) { - break; - } - if (winPtr == NULL) { - if ((dispPtr->serverWinPtr == NULL) || - (dispPtr->serverWinPtr->mainPtr == grabWinPtr->mainPtr)) { - MovePointer2(grabWinPtr, dispPtr->serverWinPtr, - NotifyUngrab, 0, 1); - } - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ReleaseButtonGrab -- - * - * This procedure is called to release a simulated button grab, if - * there is one in effect. A button grab is present whenever - * dispPtr->buttonWinPtr is non-NULL or when the GRAB_TEMP_GLOBAL - * flag is set. - * - * Results: - * None. - * - * Side effects: - * DispPtr->buttonWinPtr is reset to NULL, and enter and leave - * events are generated if necessary to move the pointer from - * the button grab window to its current window. - * - *---------------------------------------------------------------------- - */ - -static void -ReleaseButtonGrab(dispPtr) - register TkDisplay *dispPtr; /* Display whose button grab is to be - * released. */ -{ - unsigned int serial; - - if (dispPtr->buttonWinPtr != NULL) { - if (dispPtr->buttonWinPtr != dispPtr->serverWinPtr) { - MovePointer2(dispPtr->buttonWinPtr, dispPtr->serverWinPtr, - NotifyUngrab, 1, 1); - } - dispPtr->buttonWinPtr = NULL; - } - if (dispPtr->grabFlags & GRAB_TEMP_GLOBAL) { - dispPtr->grabFlags &= ~GRAB_TEMP_GLOBAL; - serial = NextRequest(dispPtr->display); - XUngrabPointer(dispPtr->display, CurrentTime); - XUngrabKeyboard(dispPtr->display, CurrentTime); - EatGrabEvents(dispPtr, serial); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkPointerEvent -- - * - * This procedure is called for each pointer-related event, before - * the event has been processed. It does various things to make - * grabs work correctly. - * - * Results: - * If the return value is 1 it means the event should be processed - * (event handlers should be invoked). If the return value is 0 - * it means the event should be ignored in order to make grabs - * work correctly. In some cases this procedure modifies the event. - * - * Side effects: - * Grab state information may be updated. New events may also be - * pushed back onto the event queue to replace or augment the - * one passed in here. - * - *---------------------------------------------------------------------- - */ - -int -TkPointerEvent(eventPtr, winPtr) - register XEvent *eventPtr; /* Pointer to the event. */ - TkWindow *winPtr; /* Tk's information for window - * where event was reported. */ -{ - register TkWindow *winPtr2; - TkDisplay *dispPtr = winPtr->dispPtr; - unsigned int serial; - int outsideGrabTree = 0; - int ancestorOfGrab = 0; - int appGrabbed = 0; /* Non-zero means event is being - * reported to an application that is - * affected by the grab. */ - - /* - * Collect information about the grab (if any). - */ - - switch (TkGrabState(winPtr)) { - case TK_GRAB_IN_TREE: - appGrabbed = 1; - break; - case TK_GRAB_ANCESTOR: - appGrabbed = 1; - outsideGrabTree = 1; - ancestorOfGrab = 1; - break; - case TK_GRAB_EXCLUDED: - appGrabbed = 1; - outsideGrabTree = 1; - break; - } - - if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { - /* - * Keep track of what window the mouse is *really* over. - * Any events that we generate have a special send_event value, - * which is detected below and used to ignore the event for - * purposes of setting serverWinPtr. - */ - - if (eventPtr->xcrossing.send_event != GENERATED_EVENT_MAGIC) { - if ((eventPtr->type == LeaveNotify) && - (winPtr->flags & TK_TOP_LEVEL)) { - dispPtr->serverWinPtr = NULL; - } else { - dispPtr->serverWinPtr = winPtr; - } - } - - /* - * When a grab is active, X continues to report enter and leave - * events for windows outside the tree of the grab window: - * 1. Detect these events and ignore them except for - * windows above the grab window. - * 2. Allow Enter and Leave events to pass through the - * windows above the grab window, but never let them - * end up with the pointer *in* one of those windows. - */ - - if (dispPtr->grabWinPtr != NULL) { - if (outsideGrabTree && appGrabbed) { - if (!ancestorOfGrab) { - return 0; - } - switch (eventPtr->xcrossing.detail) { - case NotifyInferior: - return 0; - case NotifyAncestor: - eventPtr->xcrossing.detail = NotifyVirtual; - break; - case NotifyNonlinear: - eventPtr->xcrossing.detail = NotifyNonlinearVirtual; - break; - } - } - - /* - * Make buttons have the same grab-like behavior inside a grab - * as they do outside a grab: do this by ignoring enter and - * leave events except for the window in which the button was - * pressed. - */ - - if ((dispPtr->buttonWinPtr != NULL) - && (winPtr != dispPtr->buttonWinPtr)) { - return 0; - } - } - return 1; - } - - if (!appGrabbed) { - return 1; - } - - if (eventPtr->type == MotionNotify) { - /* - * When grabs are active, X reports motion events relative to the - * window under the pointer. Instead, it should report the events - * relative to the window the button went down in, if there is a - * button down. Otherwise, if the pointer window is outside the - * subtree of the grab window, the events should be reported - * relative to the grab window. Otherwise, the event should be - * reported to the pointer window. - */ - - winPtr2 = winPtr; - if (dispPtr->buttonWinPtr != NULL) { - winPtr2 = dispPtr->buttonWinPtr; - } else if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) { - winPtr2 = dispPtr->grabWinPtr; - } - if (winPtr2 != winPtr) { - TkChangeEventWindow(eventPtr, winPtr2); - Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); - return 0; - } - return 1; - } - - /* - * Process ButtonPress and ButtonRelease events: - * 1. Keep track of whether a button is down and what window it - * went down in. - * 2. If the first button goes down outside the grab tree, pretend - * it went down in the grab window. Note: it's important to - * redirect events to the grab window like this in order to make - * things like menus work, where button presses outside the - * grabbed menu need to be seen. An application can always - * ignore the events if they occur outside its window. - * 3. If a button press or release occurs outside the window where - * the first button was pressed, retarget the event so it's reported - * to the window where the first button was pressed. - * 4. If the last button is released in a window different than where - * the first button was pressed, generate Enter/Leave events to - * move the mouse from the button window to its current window. - * 5. If the grab is set at a time when a button is already down, or - * if the window where the button was pressed was deleted, then - * dispPtr->buttonWinPtr will stay NULL. Just forget about the - * auto-grab for the button press; events will go to whatever - * window contains the pointer. If this window isn't in the grab - * tree then redirect events to the grab window. - * 6. When a button is pressed during a local grab, the X server sets - * a grab of its own, since it doesn't even know about our local - * grab. This causes enter and leave events no longer to be - * generated in the same way as for global grabs. To eliminate this - * problem, set a temporary global grab when the first button goes - * down and release it when the last button comes up. - */ - - if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) { - winPtr2 = dispPtr->buttonWinPtr; - if (winPtr2 == NULL) { - if (outsideGrabTree) { - winPtr2 = dispPtr->grabWinPtr; /* Note 5. */ - } else { - winPtr2 = winPtr; /* Note 5. */ - } - } - if (eventPtr->type == ButtonPress) { - if ((eventPtr->xbutton.state & ALL_BUTTONS) == 0) { - if (outsideGrabTree) { - TkChangeEventWindow(eventPtr, dispPtr->grabWinPtr); - Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); - return 0; /* Note 2. */ - } - if (!(dispPtr->grabFlags & GRAB_GLOBAL)) { /* Note 6. */ - serial = NextRequest(dispPtr->display); - if (XGrabPointer(dispPtr->display, - dispPtr->grabWinPtr->window, True, - ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, - GrabModeAsync, GrabModeAsync, None, None, - CurrentTime) == 0) { - EatGrabEvents(dispPtr, serial); - if (XGrabKeyboard(dispPtr->display, winPtr->window, - False, GrabModeAsync, GrabModeAsync, - CurrentTime) == 0) { - dispPtr->grabFlags |= GRAB_TEMP_GLOBAL; - } else { - XUngrabPointer(dispPtr->display, CurrentTime); - } - } - } - dispPtr->buttonWinPtr = winPtr; - return 1; - } - } else { - if ((eventPtr->xbutton.state & ALL_BUTTONS) - == buttonStates[eventPtr->xbutton.button - Button1]) { - ReleaseButtonGrab(dispPtr); /* Note 4. */ - } - } - if (winPtr2 != winPtr) { - TkChangeEventWindow(eventPtr, winPtr2); - Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD); - return 0; /* Note 3. */ - } - } - - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * TkChangeEventWindow -- - * - * Given an event and a new window to which the event should be - * retargeted, modify fields of the event so that the event is - * properly retargeted to the new window. - * - * Results: - * The following fields of eventPtr are modified: window, - * subwindow, x, y, same_screen. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkChangeEventWindow(eventPtr, winPtr) - register XEvent *eventPtr; /* Event to retarget. Must have - * type ButtonPress, ButtonRelease, KeyPress, - * KeyRelease, MotionNotify, EnterNotify, - * or LeaveNotify. */ - TkWindow *winPtr; /* New target window for event. */ -{ - int x, y, sameScreen, bd; - register TkWindow *childPtr; - - eventPtr->xmotion.window = Tk_WindowId(winPtr); - if (eventPtr->xmotion.root == - RootWindow(winPtr->display, winPtr->screenNum)) { - Tk_GetRootCoords((Tk_Window) winPtr, &x, &y); - eventPtr->xmotion.x = eventPtr->xmotion.x_root - x; - eventPtr->xmotion.y = eventPtr->xmotion.y_root - y; - eventPtr->xmotion.subwindow = None; - for (childPtr = winPtr->childList; childPtr != NULL; - childPtr = childPtr->nextPtr) { - if (childPtr->flags & TK_TOP_LEVEL) { - continue; - } - x = eventPtr->xmotion.x - childPtr->changes.x; - y = eventPtr->xmotion.y - childPtr->changes.y; - bd = childPtr->changes.border_width; - if ((x >= -bd) && (y >= -bd) - && (x < (childPtr->changes.width + bd)) - && (y < (childPtr->changes.height + bd))) { - eventPtr->xmotion.subwindow = childPtr->window; - } - } - sameScreen = 1; - } else { - eventPtr->xmotion.x = 0; - eventPtr->xmotion.y = 0; - eventPtr->xmotion.subwindow = None; - sameScreen = 0; - } - if (eventPtr->type == MotionNotify) { - eventPtr->xmotion.same_screen = sameScreen; - } else { - eventPtr->xbutton.same_screen = sameScreen; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkInOutEvents -- - * - * This procedure synthesizes EnterNotify and LeaveNotify events - * to correctly transfer the pointer from one window to another. - * It can also be used to generate FocusIn and FocusOut events - * to move the input focus. - * - * Results: - * None. - * - * Side effects: - * Synthesized events may be pushed back onto the event queue. - * The event pointed to by eventPtr is modified. - * - *---------------------------------------------------------------------- - */ - -void -TkInOutEvents(eventPtr, sourcePtr, destPtr, leaveType, enterType, position) - XEvent *eventPtr; /* A template X event. Must have all fields - * properly set except for type, window, - * subwindow, x, y, detail, and same_screen - * (Not all of these fields are valid for - * FocusIn/FocusOut events; x_root and y_root - * must be valid for Enter/Leave events, even - * though x and y needn't be valid). */ - TkWindow *sourcePtr; /* Window that used to have the pointer or - * focus (NULL means it was not in a window - * managed by this process). */ - TkWindow *destPtr; /* Window that is to end up with the pointer - * or focus (NULL means it's not one managed - * by this process). */ - int leaveType; /* Type of events to generate for windows - * being left (LeaveNotify or FocusOut). 0 - * means don't generate leave events. */ - int enterType; /* Type of events to generate for windows - * being entered (EnterNotify or FocusIn). 0 - * means don't generate enter events. */ - Tcl_QueuePosition position; /* Position at which events are added to - * the system event queue. */ -{ - register TkWindow *winPtr; - int upLevels, downLevels, i, j, focus; - - /* - * There are four possible cases to deal with: - * - * 1. SourcePtr and destPtr are the same. There's nothing to do in - * this case. - * 2. SourcePtr is an ancestor of destPtr in the same top-level - * window. Must generate events down the window tree from source - * to dest. - * 3. DestPtr is an ancestor of sourcePtr in the same top-level - * window. Must generate events up the window tree from sourcePtr - * to destPtr. - * 4. All other cases. Must first generate events up the window tree - * from sourcePtr to its top-level, then down from destPtr's - * top-level to destPtr. This form is called "non-linear." - * - * The call to FindCommonAncestor separates these four cases and decides - * how many levels up and down events have to be generated for. - */ - - if (sourcePtr == destPtr) { - return; - } - if ((leaveType == FocusOut) || (enterType == FocusIn)) { - focus = 1; - } else { - focus = 0; - } - FindCommonAncestor(sourcePtr, destPtr, &upLevels, &downLevels); - - /* - * Generate enter/leave events and add them to the grab event queue. - */ - - -#define QUEUE(w, t, d) \ - if (w->window != None) { \ - eventPtr->type = t; \ - if (focus) { \ - eventPtr->xfocus.window = w->window; \ - eventPtr->xfocus.detail = d; \ - } else { \ - eventPtr->xcrossing.detail = d; \ - TkChangeEventWindow(eventPtr, w); \ - } \ - Tk_QueueWindowEvent(eventPtr, position); \ - } - - if (downLevels == 0) { - - /* - * SourcePtr is an inferior of destPtr. - */ - - if (leaveType != 0) { - QUEUE(sourcePtr, leaveType, NotifyAncestor); - for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0; - winPtr = winPtr->parentPtr, i--) { - QUEUE(winPtr, leaveType, NotifyVirtual); - } - } - if ((enterType != 0) && (destPtr != NULL)) { - QUEUE(destPtr, enterType, NotifyInferior); - } - } else if (upLevels == 0) { - - /* - * DestPtr is an inferior of sourcePtr. - */ - - if ((leaveType != 0) && (sourcePtr != NULL)) { - QUEUE(sourcePtr, leaveType, NotifyInferior); - } - if (enterType != 0) { - for (i = downLevels-1; i > 0; i--) { - for (winPtr = destPtr->parentPtr, j = 1; j < i; - winPtr = winPtr->parentPtr, j++) { - } - QUEUE(winPtr, enterType, NotifyVirtual); - } - if (destPtr != NULL) { - QUEUE(destPtr, enterType, NotifyAncestor); - } - } - } else { - - /* - * Non-linear: neither window is an inferior of the other. - */ - - if (leaveType != 0) { - QUEUE(sourcePtr, leaveType, NotifyNonlinear); - for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0; - winPtr = winPtr->parentPtr, i--) { - QUEUE(winPtr, leaveType, NotifyNonlinearVirtual); - } - } - if (enterType != 0) { - for (i = downLevels-1; i > 0; i--) { - for (winPtr = destPtr->parentPtr, j = 1; j < i; - winPtr = winPtr->parentPtr, j++) { - } - QUEUE(winPtr, enterType, NotifyNonlinearVirtual); - } - if (destPtr != NULL) { - QUEUE(destPtr, enterType, NotifyNonlinear); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * MovePointer2 -- - * - * This procedure synthesizes EnterNotify and LeaveNotify events - * to correctly transfer the pointer from one window to another. - * It is different from TkInOutEvents in that no template X event - * needs to be supplied; this procedure generates the template - * event and calls TkInOutEvents. - * - * Results: - * None. - * - * Side effects: - * Synthesized events may be pushed back onto the event queue. - * - *---------------------------------------------------------------------- - */ - -static void -MovePointer2(sourcePtr, destPtr, mode, leaveEvents, enterEvents) - TkWindow *sourcePtr; /* Window currently containing pointer (NULL - * means it's not one managed by this - * process). */ - TkWindow *destPtr; /* Window that is to end up containing the - * pointer (NULL means it's not one managed - * by this process). */ - int mode; /* Mode for enter/leave events, such as - * NotifyNormal or NotifyUngrab. */ - int leaveEvents; /* Non-zero means generate leave events for the - * windows being left. Zero means don't - * generate leave events. */ - int enterEvents; /* Non-zero means generate enter events for the - * windows being entered. Zero means don't - * generate enter events. */ -{ - XEvent event; - Window dummy1, dummy2; - int dummy3, dummy4; - TkWindow *winPtr; - - winPtr = sourcePtr; - if ((winPtr == NULL) || (winPtr->window == None)) { - winPtr = destPtr; - if ((winPtr == NULL) || (winPtr->window == None)) { - return; - } - } - - event.xcrossing.serial = LastKnownRequestProcessed( - winPtr->display); - event.xcrossing.send_event = GENERATED_EVENT_MAGIC; - event.xcrossing.display = winPtr->display; - event.xcrossing.root = RootWindow(winPtr->display, - winPtr->screenNum); - event.xcrossing.time = TkCurrentTime(winPtr->dispPtr); - XQueryPointer(winPtr->display, winPtr->window, &dummy1, &dummy2, - &event.xcrossing.x_root, &event.xcrossing.y_root, - &dummy3, &dummy4, &event.xcrossing.state); - event.xcrossing.mode = mode; - event.xcrossing.focus = False; - TkInOutEvents(&event, sourcePtr, destPtr, (leaveEvents) ? LeaveNotify : 0, - (enterEvents) ? EnterNotify : 0, TCL_QUEUE_MARK); -} - -/* - *---------------------------------------------------------------------- - * - * TkGrabDeadWindow -- - * - * This procedure is invoked whenever a window is deleted, so that - * grab-related cleanup can be performed. - * - * Results: - * None. - * - * Side effects: - * Various cleanups happen, such as generating events to move the - * pointer back to its "natural" window as if an ungrab had been - * done. See the code. - * - *---------------------------------------------------------------------- - */ - -void -TkGrabDeadWindow(winPtr) - register TkWindow *winPtr; /* Window that is in the process - * of being deleted. */ -{ - TkDisplay *dispPtr = winPtr->dispPtr; - - if (dispPtr->eventualGrabWinPtr == winPtr) { - /* - * Grab window was deleted. Release the grab. - */ - - Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr); - } else if (dispPtr->buttonWinPtr == winPtr) { - ReleaseButtonGrab(dispPtr); - } - if (dispPtr->serverWinPtr == winPtr) { - if (winPtr->flags & TK_TOP_LEVEL) { - dispPtr->serverWinPtr = NULL; - } else { - dispPtr->serverWinPtr = winPtr->parentPtr; - } - } - if (dispPtr->grabWinPtr == winPtr) { - dispPtr->grabWinPtr = NULL; - } -} - -/* - *---------------------------------------------------------------------- - * - * EatGrabEvents -- - * - * This procedure is called to eliminate any Enter, Leave, - * FocusIn, or FocusOut events in the event queue for a - * display that have mode NotifyGrab or NotifyUngrab and - * have a serial number no less than a given value and are not - * generated by the grab module. - * - * Results: - * None. - * - * Side effects: - * DispPtr's display gets sync-ed, and some of the events get - * removed from the Tk event queue. - * - *---------------------------------------------------------------------- - */ - -static void -EatGrabEvents(dispPtr, serial) - TkDisplay *dispPtr; /* Display from which to consume events. */ - unsigned int serial; /* Only discard events that have a serial - * number at least this great. */ -{ - Tk_RestrictProc *oldProc; - GrabInfo info; - ClientData oldArg, dummy; - - info.display = dispPtr->display; - info.serial = serial; - TkpSync(info.display); - oldProc = Tk_RestrictEvents(GrabRestrictProc, (ClientData)&info, &oldArg); - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) { - } - Tk_RestrictEvents(oldProc, oldArg, &dummy); -} - -/* - *---------------------------------------------------------------------- - * - * GrabRestrictProc -- - * - * A Tk_RestrictProc used by EatGrabEvents to eliminate any - * Enter, Leave, FocusIn, or FocusOut events in the event queue - * for a display that has mode NotifyGrab or NotifyUngrab and - * have a serial number no less than a given value. - * - * Results: - * Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Tk_RestrictAction -GrabRestrictProc(arg, eventPtr) - ClientData arg; - XEvent *eventPtr; -{ - GrabInfo *info = (GrabInfo *) arg; - int mode, diff; - - /* - * The diff caculation is trickier than it may seem. Don't forget - * that serial numbers can wrap around, so can't compare the two - * serial numbers directly. - */ - - diff = eventPtr->xany.serial - info->serial; - if ((eventPtr->type == EnterNotify) - || (eventPtr->type == LeaveNotify)) { - mode = eventPtr->xcrossing.mode; - } else if ((eventPtr->type == FocusIn) - || (eventPtr->type == FocusOut)) { - mode = eventPtr->xfocus.mode; - } else { - mode = NotifyNormal; - } - if ((info->display != eventPtr->xany.display) || (mode == NotifyNormal) - || (diff < 0)) { - return TK_DEFER_EVENT; - } else { - return TK_DISCARD_EVENT; - } -} - -/* - *---------------------------------------------------------------------- - * - * QueueGrabWindowChange -- - * - * This procedure queues a special event in the Tcl event queue, - * which will cause the "grabWinPtr" field for the display to get - * modified when the event is processed. This is needed to make - * sure that the grab window changes at the proper time relative - * to grab-related enter and leave events that are also in the - * queue. In particular, this approach works even when multiple - * grabs and ungrabs happen back-to-back. - * - * Results: - * None. - * - * Side effects: - * DispPtr->grabWinPtr will be modified later (by GrabWinEventProc) - * when the event is removed from the grab event queue. - * - *---------------------------------------------------------------------- - */ - -static void -QueueGrabWindowChange(dispPtr, grabWinPtr) - TkDisplay *dispPtr; /* Display on which to change the grab - * window. */ - TkWindow *grabWinPtr; /* Window that is to become the new grab - * window (may be NULL). */ -{ - NewGrabWinEvent *grabEvPtr; - - grabEvPtr = (NewGrabWinEvent *) ckalloc(sizeof(NewGrabWinEvent)); - grabEvPtr->header.proc = GrabWinEventProc; - grabEvPtr->dispPtr = dispPtr; - if (grabWinPtr == NULL) { - grabEvPtr->grabWindow = None; - } else { - grabEvPtr->grabWindow = grabWinPtr->window; - } - Tcl_QueueEvent(&grabEvPtr->header, TCL_QUEUE_MARK); - dispPtr->eventualGrabWinPtr = grabWinPtr; -} - -/* - *---------------------------------------------------------------------- - * - * GrabWinEventProc -- - * - * This procedure is invoked as a handler for Tcl_Events of type - * NewGrabWinEvent. It updates the current grab window field in - * a display. - * - * Results: - * Returns 1 if the event was processed, 0 if it should be deferred - * for processing later. - * - * Side effects: - * The grabWinPtr field is modified in the display associated with - * the event. - * - *---------------------------------------------------------------------- - */ - -static int -GrabWinEventProc(evPtr, flags) - Tcl_Event *evPtr; /* Event of type NewGrabWinEvent. */ - int flags; /* Flags argument to Tk_DoOneEvent: indicates - * what kinds of events are being processed - * right now. */ -{ - NewGrabWinEvent *grabEvPtr = (NewGrabWinEvent *) evPtr; - - grabEvPtr->dispPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow( - grabEvPtr->dispPtr->display, grabEvPtr->grabWindow); - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * FindCommonAncestor -- - * - * Given two windows, this procedure finds their least common - * ancestor and also computes how many levels up this ancestor - * is from each of the original windows. - * - * Results: - * If the windows are in different applications or top-level - * windows, then NULL is returned and *countPtr1 and *countPtr2 - * are set to the depths of the two windows in their respective - * top-level windows (1 means the window is a top-level, 2 means - * its parent is a top-level, and so on). Otherwise, the return - * value is a pointer to the common ancestor and the counts are - * set to the distance of winPtr1 and winPtr2 from this ancestor - * (1 means they're children, 2 means grand-children, etc.). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static TkWindow * -FindCommonAncestor(winPtr1, winPtr2, countPtr1, countPtr2) - TkWindow *winPtr1; /* First window. May be NULL. */ - TkWindow *winPtr2; /* Second window. May be NULL. */ - int *countPtr1; /* Store nesting level of winPtr1 within - * common ancestor here. */ - int *countPtr2; /* Store nesting level of winPtr2 within - * common ancestor here. */ -{ - register TkWindow *winPtr; - TkWindow *ancestorPtr; - int count1, count2, i; - - /* - * Mark winPtr1 and all of its ancestors with a special flag bit. - */ - - if (winPtr1 != NULL) { - for (winPtr = winPtr1; winPtr != NULL; winPtr = winPtr->parentPtr) { - winPtr->flags |= TK_GRAB_FLAG; - if (winPtr->flags & TK_TOP_LEVEL) { - break; - } - } - } - - /* - * Search upwards from winPtr2 until an ancestor of winPtr1 is - * found or a top-level window is reached. - */ - - winPtr = winPtr2; - count2 = 0; - ancestorPtr = NULL; - if (winPtr2 != NULL) { - for (; winPtr != NULL; count2++, winPtr = winPtr->parentPtr) { - if (winPtr->flags & TK_GRAB_FLAG) { - ancestorPtr = winPtr; - break; - } - if (winPtr->flags & TK_TOP_LEVEL) { - count2++; - break; - } - } - } - - /* - * Search upwards from winPtr1 again, clearing the flag bits and - * remembering how many levels up we had to go. - */ - - if (winPtr1 == NULL) { - count1 = 0; - } else { - count1 = -1; - for (i = 0, winPtr = winPtr1; winPtr != NULL; - i++, winPtr = winPtr->parentPtr) { - winPtr->flags &= ~TK_GRAB_FLAG; - if (winPtr == ancestorPtr) { - count1 = i; - } - if (winPtr->flags & TK_TOP_LEVEL) { - if (count1 == -1) { - count1 = i+1; - } - break; - } - } - } - - *countPtr1 = count1; - *countPtr2 = count2; - return ancestorPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkPositionInTree -- - * - * Compute where the given window is relative to a particular - * subtree of the window hierarchy. - * - * Results: - * - * Returns TK_GRAB_IN_TREE if the window is contained in the - * subtree. Returns TK_GRAB_ANCESTOR if the window is an - * ancestor of the subtree, in the same toplevel. Otherwise - * it returns TK_GRAB_EXCLUDED. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkPositionInTree(winPtr, treePtr) - TkWindow *winPtr; /* Window to be checked. */ - TkWindow *treePtr; /* Root of tree to compare against. */ -{ - TkWindow *winPtr2; - - for (winPtr2 = winPtr; winPtr2 != treePtr; - winPtr2 = winPtr2->parentPtr) { - if (winPtr2 == NULL) { - for (winPtr2 = treePtr; winPtr2 != NULL; - winPtr2 = winPtr2->parentPtr) { - if (winPtr2 == winPtr) { - return TK_GRAB_ANCESTOR; - } - if (winPtr2->flags & TK_TOP_LEVEL) { - break; - } - } - return TK_GRAB_EXCLUDED; - } - } - return TK_GRAB_IN_TREE; -} - -/* - *---------------------------------------------------------------------- - * - * TkGrabState -- - * - * Given a window, this procedure returns a value that indicates - * the grab state of the application relative to the window. - * - * Results: - * The return value is one of three things: - * TK_GRAB_NONE - no grab is in effect. - * TK_GRAB_IN_TREE - there is a grab in effect, and winPtr - * is in the grabbed subtree. - * TK_GRAB_ANCESTOR - there is a grab in effect; winPtr is - * an ancestor of the grabbed window, in - * the same toplevel. - * TK_GRAB_EXCLUDED - there is a grab in effect; winPtr is - * outside the tree of the grab and is not - * an ancestor of the grabbed window in the - * same toplevel. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkGrabState(winPtr) - TkWindow *winPtr; /* Window for which grab information is - * needed. */ -{ - TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; - - if (grabWinPtr == NULL) { - return TK_GRAB_NONE; - } - if ((winPtr->mainPtr != grabWinPtr->mainPtr) - && !(winPtr->dispPtr->grabFlags & GRAB_GLOBAL)) { - return TK_GRAB_NONE; - } - - return TkPositionInTree(winPtr, grabWinPtr); -} diff --git a/generic/tkGrid.c b/generic/tkGrid.c deleted file mode 100644 index 46aa699..0000000 --- a/generic/tkGrid.c +++ /dev/null @@ -1,2615 +0,0 @@ -/* - * tkGrid.c -- - * - * Grid based geometry manager. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkGrid.c,v 1.2 1998/09/14 18:23:12 stanton Exp $ - */ - -#include "tkInt.h" - -/* - * Convenience Macros - */ - -#ifdef MAX -# undef MAX -#endif -#define MAX(x,y) ((x) > (y) ? (x) : (y)) -#ifdef MIN -# undef MIN -#endif -#define MIN(x,y) ((x) > (y) ? (y) : (x)) - -#define COLUMN (1) /* working on column offsets */ -#define ROW (2) /* working on row offsets */ - -#define CHECK_ONLY (1) /* check max slot constraint */ -#define CHECK_SPACE (2) /* alloc more space, don't change max */ - -/* - * Pre-allocate enough row and column slots for "typical" sized tables - * this value should be chosen so by the time the extra malloc's are - * required, the layout calculations overwehlm them. [A "slot" contains - * information for either a row or column, depending upon the context.] - */ - -#define TYPICAL_SIZE 25 /* (arbitrary guess) */ -#define PREALLOC 10 /* extra slots to allocate */ - -/* - * Data structures are allocated dynamically to support arbitrary sized tables. - * However, the space is proportional to the highest numbered slot with - * some non-default property. This limit is used to head off mistakes and - * denial of service attacks by limiting the amount of storage required. - */ - -#define MAX_ELEMENT 10000 - -/* - * Special characters to support relative layouts. - */ - -#define REL_SKIP 'x' /* Skip this column. */ -#define REL_HORIZ '-' /* Extend previous widget horizontally. */ -#define REL_VERT '^' /* Extend widget from row above. */ - -/* - * Structure to hold information for grid masters. A slot is either - * a row or column. - */ - -typedef struct SlotInfo { - int minSize; /* The minimum size of this slot (in pixels). - * It is set via the rowconfigure or - * columnconfigure commands. */ - int weight; /* The resize weight of this slot. (0) means - * this slot doesn't resize. Extra space in - * the layout is given distributed among slots - * inproportion to their weights. */ - int pad; /* Extra padding, in pixels, required for - * this slot. This amount is "added" to the - * largest slave in the slot. */ - int offset; /* This is a cached value used for - * introspection. It is the pixel - * offset of the right or bottom edge - * of this slot from the beginning of the - * layout. */ - int temp; /* This is a temporary value used for - * calculating adjusted weights when - * shrinking the layout below its - * nominal size. */ -} SlotInfo; - -/* - * Structure to hold information during layout calculations. There - * is one of these for each slot, an array for each of the rows or columns. - */ - -typedef struct GridLayout { - struct Gridder *binNextPtr; /* The next slave window in this bin. - * Each bin contains a list of all - * slaves whose spans are >1 and whose - * right edges fall in this slot. */ - int minSize; /* Minimum size needed for this slot, - * in pixels. This is the space required - * to hold any slaves contained entirely - * in this slot, adjusted for any slot - * constrants, such as size or padding. */ - int pad; /* Padding needed for this slot */ - int weight; /* Slot weight, controls resizing. */ - int minOffset; /* The minimum offset, in pixels, from - * the beginning of the layout to the - * right/bottom edge of the slot calculated - * from top/left to bottom/right. */ - int maxOffset; /* The maximum offset, in pixels, from - * the beginning of the layout to the - * right-or-bottom edge of the slot calculated - * from bottom-or-right to top-or-left. */ -} GridLayout; - -/* - * Keep one of these for each geometry master. - */ - -typedef struct { - SlotInfo *columnPtr; /* Pointer to array of column constraints. */ - SlotInfo *rowPtr; /* Pointer to array of row constraints. */ - int columnEnd; /* The last column occupied by any slave. */ - int columnMax; /* The number of columns with constraints. */ - int columnSpace; /* The number of slots currently allocated for - * column constraints. */ - int rowEnd; /* The last row occupied by any slave. */ - int rowMax; /* The number of rows with constraints. */ - int rowSpace; /* The number of slots currently allocated - * for row constraints. */ - int startX; /* Pixel offset of this layout within its - * parent. */ - int startY; /* Pixel offset of this layout within its - * parent. */ -} GridMaster; - -/* - * For each window that the grid cares about (either because - * the window is managed by the grid or because the window - * has slaves that are managed by the grid), there is a - * structure of the following type: - */ - -typedef struct Gridder { - Tk_Window tkwin; /* Tk token for window. NULL means that - * the window has been deleted, but the - * gridder hasn't had a chance to clean up - * yet because the structure is still in - * use. */ - struct Gridder *masterPtr; /* Master window within which this window - * is managed (NULL means this window - * isn't managed by the gridder). */ - struct Gridder *nextPtr; /* Next window managed within same - * parent. List order doesn't matter. */ - struct Gridder *slavePtr; /* First in list of slaves managed - * inside this window (NULL means - * no grid slaves). */ - GridMaster *masterDataPtr; /* Additional data for geometry master. */ - int column, row; /* Location in the grid (starting - * from zero). */ - int numCols, numRows; /* Number of columns or rows this slave spans. - * Should be at least 1. */ - int padX, padY; /* Total additional pixels to leave around the - * window (half of this space is left on each - * side). This is space *outside* the window: - * we'll allocate extra space in frame but - * won't enlarge window). */ - int iPadX, iPadY; /* Total extra pixels to allocate inside the - * window (half this amount will appear on - * each side). */ - int sticky; /* which sides of its cavity this window - * sticks to. See below for definitions */ - int doubleBw; /* Twice the window's last known border - * width. If this changes, the window - * must be re-arranged within its parent. */ - int *abortPtr; /* If non-NULL, it means that there is a nested - * call to ArrangeGrid already working on - * this window. *abortPtr may be set to 1 to - * abort that nested call. This happens, for - * example, if tkwin or any of its slaves - * is deleted. */ - int flags; /* Miscellaneous flags; see below - * for definitions. */ - - /* - * These fields are used temporarily for layout calculations only. - */ - - struct Gridder *binNextPtr; /* Link to next span>1 slave in this bin. */ - int size; /* Nominal size (width or height) in pixels - * of the slave. This includes the padding. */ -} Gridder; - -/* Flag values for "sticky"ness The 16 combinations subsume the packer's - * notion of anchor and fill. - * - * STICK_NORTH This window sticks to the top of its cavity. - * STICK_EAST This window sticks to the right edge of its cavity. - * STICK_SOUTH This window sticks to the bottom of its cavity. - * STICK_WEST This window sticks to the left edge of its cavity. - */ - -#define STICK_NORTH 1 -#define STICK_EAST 2 -#define STICK_SOUTH 4 -#define STICK_WEST 8 - -/* - * Flag values for Grid structures: - * - * REQUESTED_RELAYOUT: 1 means a Tcl_DoWhenIdle request - * has already been made to re-arrange - * all the slaves of this window. - * - * DONT_PROPAGATE: 1 means don't set this window's requested - * size. 0 means if this window is a master - * then Tk will set its requested size to fit - * the needs of its slaves. - */ - -#define REQUESTED_RELAYOUT 1 -#define DONT_PROPAGATE 2 - -/* - * Hash table used to map from Tk_Window tokens to corresponding - * Grid structures: - */ - -static Tcl_HashTable gridHashTable; -static int initialized = 0; - -/* - * Prototypes for procedures used only in this file: - */ - -static void AdjustForSticky _ANSI_ARGS_((Gridder *slavePtr, int *xPtr, - int *yPtr, int *widthPtr, int *heightPtr)); -static int AdjustOffsets _ANSI_ARGS_((int width, - int elements, SlotInfo *slotPtr)); -static void ArrangeGrid _ANSI_ARGS_((ClientData clientData)); -static int CheckSlotData _ANSI_ARGS_((Gridder *masterPtr, int slot, - int slotType, int checkOnly)); -static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int argc, char *argv[])); -static void DestroyGrid _ANSI_ARGS_((char *memPtr)); -static Gridder *GetGrid _ANSI_ARGS_((Tk_Window tkwin)); -static void GridStructureProc _ANSI_ARGS_(( - ClientData clientData, XEvent *eventPtr)); -static void GridLostSlaveProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void GridReqProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void InitMasterData _ANSI_ARGS_((Gridder *masterPtr)); -static int ResolveConstraints _ANSI_ARGS_((Gridder *gridPtr, - int rowOrColumn, int maxOffset)); -static void SetGridSize _ANSI_ARGS_((Gridder *gridPtr)); -static void StickyToString _ANSI_ARGS_((int flags, char *result)); -static int StringToSticky _ANSI_ARGS_((char *string)); -static void Unlink _ANSI_ARGS_((Gridder *gridPtr)); - -static Tk_GeomMgr gridMgrType = { - "grid", /* name */ - GridReqProc, /* requestProc */ - GridLostSlaveProc, /* lostSlaveProc */ -}; - -/* - *-------------------------------------------------------------- - * - * Tk_GridCmd -- - * - * This procedure is invoked to process the "grid" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_GridCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - Gridder *masterPtr; /* master grid record */ - GridMaster *gridPtr; /* pointer to grid data */ - size_t length; /* streing length of argument */ - char c; /* 1st character of argument */ - - if ((argc >= 2) && ((argv[1][0] == '.') || (argv[1][0] == REL_SKIP) || - (argv[1][0] == REL_VERT))) { - return ConfigureSlaves(interp, tkwin, argc-1, argv+1); - } - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option arg ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - - if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - Tk_Window master; - int row, column; /* origin for bounding box */ - int row2, column2; /* end of bounding box */ - int endX, endY; /* last column/row in the layout */ - int x=0, y=0; /* starting pixels for this bounding box */ - int width, height; /* size of the bounding box */ - - if (argc!=3 && argc != 5 && argc != 7) { - Tcl_AppendResult(interp, "wrong number of arguments: ", - "must be \"",argv[0], - " bbox master ?column row ?column row??\"", - (char *) NULL); - return TCL_ERROR; - } - - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetGrid(master); - - if (argc >= 5) { - if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) { - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) { - return TCL_ERROR; - } - column2 = column; - row2 = row; - } - - if (argc == 7) { - if (Tcl_GetInt(interp, argv[5], &column2) != TCL_OK) { - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[6], &row2) != TCL_OK) { - return TCL_ERROR; - } - } - - gridPtr = masterPtr->masterDataPtr; - if (gridPtr == NULL) { - sprintf(interp->result, "%d %d %d %d",0,0,0,0); - return(TCL_OK); - } - - SetGridSize(masterPtr); - endX = MAX(gridPtr->columnEnd, gridPtr->columnMax); - endY = MAX(gridPtr->rowEnd, gridPtr->rowMax); - - if ((endX == 0) || (endY == 0)) { - sprintf(interp->result, "%d %d %d %d",0,0,0,0); - return(TCL_OK); - } - if (argc == 3) { - row = column = 0; - row2 = endY; - column2 = endX; - } - - if (column > column2) { - int temp = column; - column = column2, column2 = temp; - } - if (row > row2) { - int temp = row; - row = row2, row2 = temp; - } - - if (column > 0 && column < endX) { - x = gridPtr->columnPtr[column-1].offset; - } else if (column > 0) { - x = gridPtr->columnPtr[endX-1].offset; - } - - if (row > 0 && row < endY) { - y = gridPtr->rowPtr[row-1].offset; - } else if (row > 0) { - y = gridPtr->rowPtr[endY-1].offset; - } - - if (column2 < 0) { - width = 0; - } else if (column2 >= endX) { - width = gridPtr->columnPtr[endX-1].offset - x; - } else { - width = gridPtr->columnPtr[column2].offset - x; - } - - if (row2 < 0) { - height = 0; - } else if (row2 >= endY) { - height = gridPtr->rowPtr[endY-1].offset - y; - } else { - height = gridPtr->rowPtr[row2].offset - y; - } - - sprintf(interp->result, "%d %d %d %d", - x + gridPtr->startX, y + gridPtr->startY, width, height); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { - if (argv[2][0] != '.') { - Tcl_AppendResult(interp, "bad argument \"", argv[2], - "\": must be name of window", (char *) NULL); - return TCL_ERROR; - } - return ConfigureSlaves(interp, tkwin, argc-2, argv+2); - } else if (((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) || - ((c == 'r') && (strncmp(argv[1], "remove", length) == 0))) { - Tk_Window slave; - Gridder *slavePtr; - int i; - - for (i = 2; i < argc; i++) { - slave = Tk_NameToWindow(interp, argv[i], tkwin); - if (slave == NULL) { - return TCL_ERROR; - } - slavePtr = GetGrid(slave); - if (slavePtr->masterPtr != NULL) { - - /* - * For "forget", reset all the settings to their defaults - */ - - if (c == 'f') { - slavePtr->column = slavePtr->row = -1; - slavePtr->numCols = 1; - slavePtr->numRows = 1; - slavePtr->padX = slavePtr->padY = 0; - slavePtr->iPadX = slavePtr->iPadY = 0; - slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width; - slavePtr->flags = 0; - slavePtr->sticky = 0; - } - Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, - slavePtr->masterPtr->tkwin); - } - Unlink(slavePtr); - Tk_UnmapWindow(slavePtr->tkwin); - } - } - } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { - register Gridder *slavePtr; - Tk_Window slave; - char buffer[70]; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " info window\"", (char *) NULL); - return TCL_ERROR; - } - slave = Tk_NameToWindow(interp, argv[2], tkwin); - if (slave == NULL) { - return TCL_ERROR; - } - slavePtr = GetGrid(slave); - if (slavePtr->masterPtr == NULL) { - interp->result[0] = '\0'; - return TCL_OK; - } - - Tcl_AppendElement(interp, "-in"); - Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin)); - sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d", - slavePtr->column, slavePtr->row, - slavePtr->numCols, slavePtr->numRows); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d", - slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2, - slavePtr->padY/2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - StickyToString(slavePtr->sticky,buffer); - Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL); - } else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) { - Tk_Window master; - register SlotInfo *slotPtr; - int x, y; /* Offset in pixels, from edge of parent. */ - int i, j; /* Corresponding column and row indeces. */ - int endX, endY; /* end of grid */ - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " location master x y\"", (char *)NULL); - return TCL_ERROR; - } - - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - - if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) { - return TCL_ERROR; - } - if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) { - return TCL_ERROR; - } - - masterPtr = GetGrid(master); - if (masterPtr->masterDataPtr == NULL) { - sprintf(interp->result, "%d %d", -1, -1); - return TCL_OK; - } - gridPtr = masterPtr->masterDataPtr; - - /* - * Update any pending requests. This is not always the - * steady state value, as more configure events could be in - * the pipeline, but its as close as its easy to get. - */ - - while (masterPtr->flags & REQUESTED_RELAYOUT) { - Tk_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr); - ArrangeGrid ((ClientData) masterPtr); - } - SetGridSize(masterPtr); - endX = MAX(gridPtr->columnEnd, gridPtr->columnMax); - endY = MAX(gridPtr->rowEnd, gridPtr->rowMax); - - slotPtr = masterPtr->masterDataPtr->columnPtr; - if (x < masterPtr->masterDataPtr->startX) { - i = -1; - } else { - x -= masterPtr->masterDataPtr->startX; - for (i=0;slotPtr[i].offset < x && i < endX; i++) { - /* null body */ - } - } - - slotPtr = masterPtr->masterDataPtr->rowPtr; - if (y < masterPtr->masterDataPtr->startY) { - j = -1; - } else { - y -= masterPtr->masterDataPtr->startY; - for (j=0;slotPtr[j].offset < y && j < endY; j++) { - /* null body */ - } - } - - sprintf(interp->result, "%d %d", i, j); - } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) { - Tk_Window master; - int propagate; - - if (argc > 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " propagate window ?boolean?\"", - (char *) NULL); - return TCL_ERROR; - } - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetGrid(master); - if (argc == 3) { - interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"; - return TCL_OK; - } - if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) { - return TCL_ERROR; - } - if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) { - masterPtr->flags ^= DONT_PROPAGATE; - - /* - * Re-arrange the master to allow new geometry information to - * propagate upwards to the master's master. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_RELAYOUT)) { - masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr); - } - } - } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0) - && (length > 1)) { - Tk_Window master; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " size window\"", (char *) NULL); - return TCL_ERROR; - } - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetGrid(master); - - if (masterPtr->masterDataPtr != NULL) { - SetGridSize(masterPtr); - gridPtr = masterPtr->masterDataPtr; - sprintf(interp->result, "%d %d", - MAX(gridPtr->columnEnd, gridPtr->columnMax), - MAX(gridPtr->rowEnd, gridPtr->rowMax)); - } else { - sprintf(interp->result, "%d %d",0, 0); - } - } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0) - && (length > 1)) { - Tk_Window master; - Gridder *slavePtr; - int i, value; - int row = -1, column = -1; - - if ((argc < 3) || ((argc%2) == 0)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " slaves window ?-option value...?\"", - (char *) NULL); - return TCL_ERROR; - } - - for (i=3; i<argc; i+=2) { - length = strlen(argv[i]); - if ((*argv[i] != '-') || (length < 2)) { - Tcl_AppendResult(interp, "invalid args: should be \"", - argv[0], " slaves window ?-option value...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) { - return TCL_ERROR; - } - if (value < 0) { - Tcl_AppendResult(interp, argv[i], - " is an invalid value: should NOT be < 0", - (char *) NULL); - return TCL_ERROR; - } - if (strncmp(argv[i], "-column", length) == 0) { - column = value; - } else if (strncmp(argv[i], "-row", length) == 0) { - row = value; - } else { - Tcl_AppendResult(interp, argv[i], - " is an invalid option: should be \"", - "-row, -column\"", - (char *) NULL); - return TCL_ERROR; - } - } - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetGrid(master); - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - if (column>=0 && (slavePtr->column > column - || slavePtr->column+slavePtr->numCols-1 < column)) { - continue; - } - if (row>=0 && (slavePtr->row > row || - slavePtr->row+slavePtr->numRows-1 < row)) { - continue; - } - Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin)); - } - - /* - * Sample argument combinations: - * grid columnconfigure <master> <index> -option - * grid columnconfigure <master> <index> -option value -option value - * grid rowconfigure <master> <index> - * grid rowconfigure <master> <index> -option - * grid rowconfigure <master> <index> -option value -option value. - */ - - } else if(((c == 'c') && (strncmp(argv[1], "columnconfigure", length) == 0) - && (length >= 3)) || - ((c == 'r') && (strncmp(argv[1], "rowconfigure", length) == 0) - && (length >=2))) { - Tk_Window master; - SlotInfo *slotPtr = NULL; - int slot; /* the column or row number */ - size_t length; /* the # of chars in the "-option" string */ - int slotType; /* COLUMN or ROW */ - int size; /* the configuration value */ - int checkOnly; /* check the size only */ - int argcPtr; /* Number of items in index list */ - char **argvPtr; /* array of indeces */ - char **indexP; /* String value of current index list item. */ - int ok; /* temporary TCL result code */ - int i; - - if (((argc%2 != 0) && (argc>6)) || (argc < 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " master index ?-option value...?\"", - (char *)NULL); - return TCL_ERROR; - } - - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - - if (Tcl_SplitList(interp, argv[3], &argcPtr, &argvPtr) != TCL_OK) { - return TCL_ERROR; - } - - checkOnly = ((argc == 4) || (argc == 5)); - masterPtr = GetGrid(master); - slotType = (c == 'c') ? COLUMN : ROW; - if (checkOnly && argcPtr > 1) { - Tcl_AppendResult(interp, argv[3], - " must be a single element.", (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } - for (indexP=argvPtr; *indexP != NULL; indexP++) { - if (Tcl_GetInt(interp, *indexP, &slot) != TCL_OK) { - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } - ok = CheckSlotData(masterPtr, slot, slotType, checkOnly); - if ((ok!=TCL_OK) && ((argc<4) || (argc>5))) { - Tcl_AppendResult(interp, argv[0], - " ", argv[1], ": \"", *argvPtr,"\" is out of range", - (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else if (ok == TCL_OK) { - slotPtr = (slotType == COLUMN) ? - masterPtr->masterDataPtr->columnPtr : - masterPtr->masterDataPtr->rowPtr; - } - - /* - * Return all of the options for this row or column. If the - * request is out of range, return all 0's. - */ - - if (argc == 4) { - Tcl_Free((char *)argvPtr); - } - if ((argc == 4) && (ok == TCL_OK)) { - sprintf(interp->result,"-minsize %d -pad %d -weight %d", - slotPtr[slot].minSize,slotPtr[slot].pad, - slotPtr[slot].weight); - return (TCL_OK); - } else if (argc == 4) { - sprintf(interp->result,"-minsize %d -pad %d -weight %d", 0,0,0); - return (TCL_OK); - } - - /* - * Loop through each option value pair, setting the values as required. - * If only one option is given, with no value, the current value is - * returned. - */ - - for (i=4; i<argc; i+=2) { - length = strlen(argv[i]); - if ((*argv[i] != '-') || length < 2) { - Tcl_AppendResult(interp, "invalid arg \"", - argv[i], "\" :expecting -minsize, -pad, or -weight.", - (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } - if (strncmp(argv[i], "-minsize", length) == 0) { - if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].minSize : 0; - sprintf(interp->result,"%d",value); - } else if (Tk_GetPixels(interp, master, argv[i+1], &size) - != TCL_OK) { - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else { - slotPtr[slot].minSize = size; - } - } - else if (strncmp(argv[i], "-weight", length) == 0) { - int wt; - if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].weight : 0; - sprintf(interp->result,"%d",value); - } else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) { - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else if (wt < 0) { - Tcl_AppendResult(interp, "invalid arg \"", argv[i], - "\": should be non-negative", (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else { - slotPtr[slot].weight = wt; - } - } - else if (strncmp(argv[i], "-pad", length) == 0) { - if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].pad : 0; - sprintf(interp->result,"%d",value); - } else if (Tk_GetPixels(interp, master, argv[i+1], &size) - != TCL_OK) { - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else if (size < 0) { - Tcl_AppendResult(interp, "invalid arg \"", argv[i], - "\": should be non-negative", (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } else { - slotPtr[slot].pad = size; - } - } else { - Tcl_AppendResult(interp, "invalid arg \"", - argv[i], "\": expecting -minsize, -pad, or -weight.", - (char *) NULL); - Tcl_Free((char *)argvPtr); - return TCL_ERROR; - } - } - } - Tcl_Free((char *)argvPtr); - - /* - * If we changed a property, re-arrange the table, - * and check for constraint shrinkage. - */ - - if (argc != 5) { - if (slotType == ROW) { - int last = masterPtr->masterDataPtr->rowMax - 1; - while ((last >= 0) && (slotPtr[last].weight == 0) - && (slotPtr[last].pad == 0) - && (slotPtr[last].minSize == 0)) { - last--; - } - masterPtr->masterDataPtr->rowMax = last+1; - } else { - int last = masterPtr->masterDataPtr->columnMax - 1; - while ((last >= 0) && (slotPtr[last].weight == 0) - && (slotPtr[last].pad == 0) - && (slotPtr[last].minSize == 0)) { - last--; - } - masterPtr->masterDataPtr->columnMax = last + 1; - } - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_RELAYOUT)) { - masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr); - } - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be bbox, columnconfigure, configure, forget, info, ", - "location, propagate, remove, rowconfigure, size, or slaves.", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * GridReqProc -- - * - * This procedure is invoked by Tk_GeometryRequest for - * windows managed by the grid. - * - * Results: - * None. - * - * Side effects: - * Arranges for tkwin, and all its managed siblings, to - * be re-arranged at the next idle point. - * - *-------------------------------------------------------------- - */ - -static void -GridReqProc(clientData, tkwin) - ClientData clientData; /* Grid's information about - * window that got new preferred - * geometry. */ - Tk_Window tkwin; /* Other Tk-related information - * about the window. */ -{ - register Gridder *gridPtr = (Gridder *) clientData; - - gridPtr = gridPtr->masterPtr; - if (!(gridPtr->flags & REQUESTED_RELAYOUT)) { - gridPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * GridLostSlaveProc -- - * - * This procedure is invoked by Tk whenever some other geometry - * claims control over a slave that used to be managed by us. - * - * Results: - * None. - * - * Side effects: - * Forgets all grid-related information about the slave. - * - *-------------------------------------------------------------- - */ - -static void -GridLostSlaveProc(clientData, tkwin) - ClientData clientData; /* Grid structure for slave window that - * was stolen away. */ - Tk_Window tkwin; /* Tk's handle for the slave window. */ -{ - register Gridder *slavePtr = (Gridder *) clientData; - - if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); - } - Unlink(slavePtr); - Tk_UnmapWindow(slavePtr->tkwin); -} - -/* - *-------------------------------------------------------------- - * - * AdjustOffsets -- - * - * This procedure adjusts the size of the layout to fit in the - * space provided. If it needs more space, the extra is added - * according to the weights. If it needs less, the space is removed - * according to the weights, but at no time does the size drop below - * the minsize specified for that slot. - * - * Results: - * The initial offset of the layout, - * if all the weights are zero, else 0. - * - * Side effects: - * The slot offsets are modified to shrink the layout. - * - *-------------------------------------------------------------- - */ - -static int -AdjustOffsets(size, slots, slotPtr) - int size; /* The total layout size (in pixels). */ - int slots; /* Number of slots. */ - register SlotInfo *slotPtr; /* Pointer to slot array. */ -{ - register int slot; /* Current slot. */ - int diff; /* Extra pixels needed to add to the layout. */ - int totalWeight = 0; /* Sum of the weights for all the slots. */ - int weight = 0; /* Sum of the weights so far. */ - int minSize = 0; /* Minimum possible layout size. */ - int newDiff; /* The most pixels that can be added on - * the current pass. */ - - diff = size - slotPtr[slots-1].offset; - - /* - * The layout is already the correct size; all done. - */ - - if (diff == 0) { - return(0); - } - - /* - * If all the weights are zero, center the layout in its parent if - * there is extra space, else clip on the bottom/right. - */ - - for (slot=0; slot < slots; slot++) { - totalWeight += slotPtr[slot].weight; - } - - if (totalWeight == 0 ) { - return(diff > 0 ? diff/2 : 0); - } - - /* - * Add extra space according to the slot weights. This is done - * cumulatively to prevent round-off error accumulation. - */ - - if (diff > 0) { - for (weight=slot=0; slot < slots; slot++) { - weight += slotPtr[slot].weight; - slotPtr[slot].offset += diff * weight / totalWeight; - } - return(0); - } - - /* - * The layout must shrink below its requested size. Compute the - * minimum possible size by looking at the slot minSizes. - */ - - for (slot=0; slot < slots; slot++) { - if (slotPtr[slot].weight > 0) { - minSize += slotPtr[slot].minSize; - } else if (slot > 0) { - minSize += slotPtr[slot].offset - slotPtr[slot-1].offset; - } else { - minSize += slotPtr[slot].offset; - } - } - - /* - * If the requested size is less than the minimum required size, - * set the slot sizes to their minimum values, then clip on the - * bottom/right. - */ - - if (size <= minSize) { - int offset = 0; - for (slot=0; slot < slots; slot++) { - if (slotPtr[slot].weight > 0) { - offset += slotPtr[slot].minSize; - } else if (slot > 0) { - offset += slotPtr[slot].offset - slotPtr[slot-1].offset; - } else { - offset += slotPtr[slot].offset; - } - slotPtr[slot].offset = offset; - } - return(0); - } - - /* - * Remove space from slots according to their weights. The weights - * get renormalized anytime a slot shrinks to its minimum size. - */ - - while (diff < 0) { - - /* - * Find the total weight for the shrinkable slots. - */ - - for (totalWeight=slot=0; slot < slots; slot++) { - int current = (slot == 0) ? slotPtr[slot].offset : - slotPtr[slot].offset - slotPtr[slot-1].offset; - if (current > slotPtr[slot].minSize) { - totalWeight += slotPtr[slot].weight; - slotPtr[slot].temp = slotPtr[slot].weight; - } else { - slotPtr[slot].temp = 0; - } - } - if (totalWeight == 0) { - break; - } - - /* - * Find the maximum amount of space we can distribute this pass. - */ - - newDiff = diff; - for (slot = 0; slot < slots; slot++) { - int current; /* current size of this slot */ - int maxDiff; /* max diff that would cause - * this slot to equal its minsize */ - if (slotPtr[slot].temp == 0) { - continue; - } - current = (slot == 0) ? slotPtr[slot].offset : - slotPtr[slot].offset - slotPtr[slot-1].offset; - maxDiff = totalWeight * (slotPtr[slot].minSize - current) - / slotPtr[slot].temp; - if (maxDiff > newDiff) { - newDiff = maxDiff; - } - } - - /* - * Now distribute the space. - */ - - for (weight=slot=0; slot < slots; slot++) { - weight += slotPtr[slot].temp; - slotPtr[slot].offset += newDiff * weight / totalWeight; - } - diff -= newDiff; - } - return(0); -} - -/* - *-------------------------------------------------------------- - * - * AdjustForSticky -- - * - * This procedure adjusts the size of a slave in its cavity based - * on its "sticky" flags. - * - * Results: - * The input x, y, width, and height are changed to represent the - * desired coordinates of the slave. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -AdjustForSticky(slavePtr, xPtr, yPtr, widthPtr, heightPtr) - Gridder *slavePtr; /* Slave window to arrange in its cavity. */ - int *xPtr; /* Pixel location of the left edge of the cavity. */ - int *yPtr; /* Pixel location of the top edge of the cavity. */ - int *widthPtr; /* Width of the cavity (in pixels). */ - int *heightPtr; /* Height of the cavity (in pixels). */ -{ - int diffx=0; /* Cavity width - slave width. */ - int diffy=0; /* Cavity hight - slave height. */ - int sticky = slavePtr->sticky; - - *xPtr += slavePtr->padX/2; - *widthPtr -= slavePtr->padX; - *yPtr += slavePtr->padY/2; - *heightPtr -= slavePtr->padY; - - if (*widthPtr > (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX)) { - diffx = *widthPtr - (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX); - *widthPtr = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX; - } - - if (*heightPtr > (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY)) { - diffy = *heightPtr - (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY); - *heightPtr = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY; - } - - if (sticky&STICK_EAST && sticky&STICK_WEST) { - *widthPtr += diffx; - } - if (sticky&STICK_NORTH && sticky&STICK_SOUTH) { - *heightPtr += diffy; - } - if (!(sticky&STICK_WEST)) { - *xPtr += (sticky&STICK_EAST) ? diffx : diffx/2; - } - if (!(sticky&STICK_NORTH)) { - *yPtr += (sticky&STICK_SOUTH) ? diffy : diffy/2; - } -} - -/* - *-------------------------------------------------------------- - * - * ArrangeGrid -- - * - * This procedure is invoked (using the Tcl_DoWhenIdle - * mechanism) to re-layout a set of windows managed by - * the grid. It is invoked at idle time so that a - * series of grid requests can be merged into a single - * layout operation. - * - * Results: - * None. - * - * Side effects: - * The slaves of masterPtr may get resized or moved. - * - *-------------------------------------------------------------- - */ - -static void -ArrangeGrid(clientData) - ClientData clientData; /* Structure describing parent whose slaves - * are to be re-layed out. */ -{ - register Gridder *masterPtr = (Gridder *) clientData; - register Gridder *slavePtr; - GridMaster *slotPtr = masterPtr->masterDataPtr; - int abort; - int width, height; /* requested size of layout, in pixels */ - int realWidth, realHeight; /* actual size layout should take-up */ - - masterPtr->flags &= ~REQUESTED_RELAYOUT; - - /* - * If the parent has no slaves anymore, then don't do anything - * at all: just leave the parent's size as-is. Otherwise there is - * no way to "relinquish" control over the parent so another geometry - * manager can take over. - */ - - if (masterPtr->slavePtr == NULL) { - return; - } - - if (masterPtr->masterDataPtr == NULL) { - return; - } - - /* - * Abort any nested call to ArrangeGrid for this window, since - * we'll do everything necessary here, and set up so this call - * can be aborted if necessary. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - masterPtr->abortPtr = &abort; - abort = 0; - Tcl_Preserve((ClientData) masterPtr); - - /* - * Call the constraint engine to fill in the row and column offsets. - */ - - SetGridSize(masterPtr); - width = ResolveConstraints(masterPtr, COLUMN, 0); - height = ResolveConstraints(masterPtr, ROW, 0); - width += 2*Tk_InternalBorderWidth(masterPtr->tkwin); - height += 2*Tk_InternalBorderWidth(masterPtr->tkwin); - - if (((width != Tk_ReqWidth(masterPtr->tkwin)) - || (height != Tk_ReqHeight(masterPtr->tkwin))) - && !(masterPtr->flags & DONT_PROPAGATE)) { - Tk_GeometryRequest(masterPtr->tkwin, width, height); - if (width>1 && height>1) { - masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr); - } - masterPtr->abortPtr = NULL; - Tcl_Release((ClientData) masterPtr); - return; - } - - /* - * If the currently requested layout size doesn't match the parent's - * window size, then adjust the slot offsets according to the - * weights. If all of the weights are zero, center the layout in - * its parent. I haven't decided what to do if the parent is smaller - * than the requested size. - */ - - realWidth = Tk_Width(masterPtr->tkwin) - - 2*Tk_InternalBorderWidth(masterPtr->tkwin); - realHeight = Tk_Height(masterPtr->tkwin) - - 2*Tk_InternalBorderWidth(masterPtr->tkwin); - slotPtr->startX = AdjustOffsets(realWidth, - MAX(slotPtr->columnEnd,slotPtr->columnMax), slotPtr->columnPtr); - slotPtr->startY = AdjustOffsets(realHeight, - MAX(slotPtr->rowEnd,slotPtr->rowMax), slotPtr->rowPtr); - slotPtr->startX += Tk_InternalBorderWidth(masterPtr->tkwin); - slotPtr->startY += Tk_InternalBorderWidth(masterPtr->tkwin); - - /* - * Now adjust the actual size of the slave to its cavity by - * computing the cavity size, and adjusting the widget according - * to its stickyness. - */ - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort; - slavePtr = slavePtr->nextPtr) { - int x, y; /* top left coordinate */ - int width, height; /* slot or slave size */ - int col = slavePtr->column; - int row = slavePtr->row; - - x = (col>0) ? slotPtr->columnPtr[col-1].offset : 0; - y = (row>0) ? slotPtr->rowPtr[row-1].offset : 0; - - width = slotPtr->columnPtr[slavePtr->numCols+col-1].offset - x; - height = slotPtr->rowPtr[slavePtr->numRows+row-1].offset - y; - - x += slotPtr->startX; - y += slotPtr->startY; - - AdjustForSticky(slavePtr, &x, &y, &width, &height); - - /* - * Now put the window in the proper spot. (This was taken directly - * from tkPack.c.) If the slave is a child of the master, then - * do this here. Otherwise let Tk_MaintainGeometry do the work. - */ - - if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) { - if ((width <= 0) || (height <= 0)) { - Tk_UnmapWindow(slavePtr->tkwin); - } else { - if ((x != Tk_X(slavePtr->tkwin)) - || (y != Tk_Y(slavePtr->tkwin)) - || (width != Tk_Width(slavePtr->tkwin)) - || (height != Tk_Height(slavePtr->tkwin))) { - Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height); - } - if (abort) { - break; - } - - /* - * Don't map the slave if the master isn't mapped: wait - * until the master gets mapped later. - */ - - if (Tk_IsMapped(masterPtr->tkwin)) { - Tk_MapWindow(slavePtr->tkwin); - } - } - } else { - if ((width <= 0) || (height <= 0)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin); - Tk_UnmapWindow(slavePtr->tkwin); - } else { - Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin, - x, y, width, height); - } - } - } - - masterPtr->abortPtr = NULL; - Tcl_Release((ClientData) masterPtr); -} - -/* - *-------------------------------------------------------------- - * - * ResolveConstraints -- - * - * Resolve all of the column and row boundaries. Most of - * the calculations are identical for rows and columns, so this procedure - * is called twice, once for rows, and again for columns. - * - * Results: - * The offset (in pixels) from the left/top edge of this layout is - * returned. - * - * Side effects: - * The slot offsets are copied into the SlotInfo structure for the - * geometry master. - * - *-------------------------------------------------------------- - */ - -static int -ResolveConstraints(masterPtr, slotType, maxOffset) - Gridder *masterPtr; /* The geometry master for this grid. */ - int slotType; /* Either ROW or COLUMN. */ - int maxOffset; /* The actual maximum size of this layout - * in pixels, or 0 (not currently used). */ -{ - register SlotInfo *slotPtr; /* Pointer to row/col constraints. */ - register Gridder *slavePtr; /* List of slave windows in this grid. */ - int constraintCount; /* Count of rows or columns that have - * constraints. */ - int slotCount; /* Last occupied row or column. */ - int gridCount; /* The larger of slotCount and constraintCount. - */ - GridLayout *layoutPtr; /* Temporary layout structure. */ - int requiredSize; /* The natural size of the grid (pixels). - * This is the minimum size needed to - * accomodate all of the slaves at their - * requested sizes. */ - int offset; /* The pixel offset of the right edge of the - * current slot from the beginning of the - * layout. */ - int slot; /* The current slot. */ - int start; /* The first slot of a contiguous set whose - * constraints are not yet fully resolved. */ - int end; /* The Last slot of a contiguous set whose - * constraints are not yet fully resolved. */ - - /* - * For typical sized tables, we'll use stack space for the layout data - * to avoid the overhead of a malloc and free for every layout. - */ - - GridLayout layoutData[TYPICAL_SIZE + 1]; - - if (slotType == COLUMN) { - constraintCount = masterPtr->masterDataPtr->columnMax; - slotCount = masterPtr->masterDataPtr->columnEnd; - slotPtr = masterPtr->masterDataPtr->columnPtr; - } else { - constraintCount = masterPtr->masterDataPtr->rowMax; - slotCount = masterPtr->masterDataPtr->rowEnd; - slotPtr = masterPtr->masterDataPtr->rowPtr; - } - - /* - * Make sure there is enough memory for the layout. - */ - - gridCount = MAX(constraintCount,slotCount); - if (gridCount >= TYPICAL_SIZE) { - layoutPtr = (GridLayout *) Tcl_Alloc(sizeof(GridLayout) * (1+gridCount)); - } else { - layoutPtr = layoutData; - } - - /* - * Allocate an extra layout slot to represent the left/top edge of - * the 0th slot to make it easier to calculate slot widths from - * offsets without special case code. - * Initialize the "dummy" slot to the left/top of the table. - * This slot avoids special casing the first slot. - */ - - layoutPtr->minOffset = 0; - layoutPtr->maxOffset = 0; - layoutPtr++; - - /* - * Step 1. - * Copy the slot constraints into the layout structure, - * and initialize the rest of the fields. - */ - - for (slot=0; slot < constraintCount; slot++) { - layoutPtr[slot].minSize = slotPtr[slot].minSize; - layoutPtr[slot].weight = slotPtr[slot].weight; - layoutPtr[slot].pad = slotPtr[slot].pad; - layoutPtr[slot].binNextPtr = NULL; - } - for(;slot<gridCount;slot++) { - layoutPtr[slot].minSize = 0; - layoutPtr[slot].weight = 0; - layoutPtr[slot].pad = 0; - layoutPtr[slot].binNextPtr = NULL; - } - - /* - * Step 2. - * Slaves with a span of 1 are used to determine the minimum size of - * each slot. Slaves whose span is two or more slots don't - * contribute to the minimum size of each slot directly, but can cause - * slots to grow if their size exceeds the the sizes of the slots they - * span. - * - * Bin all slaves whose spans are > 1 by their right edges. This - * allows the computation on minimum and maximum possible layout - * sizes at each slot boundary, without the need to re-sort the slaves. - */ - - switch (slotType) { - case COLUMN: - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - int rightEdge = slavePtr->column + slavePtr->numCols - 1; - slavePtr->size = Tk_ReqWidth(slavePtr->tkwin) + - slavePtr->padX + slavePtr->iPadX + slavePtr->doubleBw; - if (slavePtr->numCols > 1) { - slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr; - layoutPtr[rightEdge].binNextPtr = slavePtr; - } else { - int size = slavePtr->size + layoutPtr[rightEdge].pad; - if (size > layoutPtr[rightEdge].minSize) { - layoutPtr[rightEdge].minSize = size; - } - } - } - break; - case ROW: - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - int rightEdge = slavePtr->row + slavePtr->numRows - 1; - slavePtr->size = Tk_ReqHeight(slavePtr->tkwin) + - slavePtr->padY + slavePtr->iPadY + slavePtr->doubleBw; - if (slavePtr->numRows > 1) { - slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr; - layoutPtr[rightEdge].binNextPtr = slavePtr; - } else { - int size = slavePtr->size + layoutPtr[rightEdge].pad; - if (size > layoutPtr[rightEdge].minSize) { - layoutPtr[rightEdge].minSize = size; - } - } - } - break; - } - - /* - * Step 3. - * Determine the minimum slot offsets going from left to right - * that would fit all of the slaves. This determines the minimum - */ - - for (offset=slot=0; slot < gridCount; slot++) { - layoutPtr[slot].minOffset = layoutPtr[slot].minSize + offset; - for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL; - slavePtr = slavePtr->binNextPtr) { - int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows; - int required = slavePtr->size + layoutPtr[slot - span].minOffset; - if (required > layoutPtr[slot].minOffset) { - layoutPtr[slot].minOffset = required; - } - } - offset = layoutPtr[slot].minOffset; - } - - /* - * At this point, we know the minimum required size of the entire layout. - * It might be prudent to stop here if our "master" will resize itself - * to this size. - */ - - requiredSize = offset; - if (maxOffset > offset) { - offset=maxOffset; - } - - /* - * Step 4. - * Determine the minimum slot offsets going from right to left, - * bounding the pixel range of each slot boundary. - * Pre-fill all of the right offsets with the actual size of the table; - * they will be reduced as required. - */ - - for (slot=0; slot < gridCount; slot++) { - layoutPtr[slot].maxOffset = offset; - } - for (slot=gridCount-1; slot > 0;) { - for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL; - slavePtr = slavePtr->binNextPtr) { - int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows; - int require = offset - slavePtr->size; - int startSlot = slot - span; - if (startSlot >=0 && require < layoutPtr[startSlot].maxOffset) { - layoutPtr[startSlot].maxOffset = require; - } - } - offset -= layoutPtr[slot].minSize; - slot--; - if (layoutPtr[slot].maxOffset < offset) { - offset = layoutPtr[slot].maxOffset; - } else { - layoutPtr[slot].maxOffset = offset; - } - } - - /* - * Step 5. - * At this point, each slot boundary has a range of values that - * will satisfy the overall layout size. - * Make repeated passes over the layout structure looking for - * spans of slot boundaries where the minOffsets are less than - * the maxOffsets, and adjust the offsets according to the slot - * weights. At each pass, at least one slot boundary will have - * its range of possible values fixed at a single value. - */ - - for (start=0; start < gridCount;) { - int totalWeight = 0; /* Sum of the weights for all of the - * slots in this span. */ - int need = 0; /* The minimum space needed to layout - * this span. */ - int have; /* The actual amount of space that will - * be taken up by this span. */ - int weight; /* Cumulative weights of the columns in - * this span. */ - int noWeights = 0; /* True if the span has no weights. */ - - /* - * Find a span by identifying ranges of slots whose edges are - * already constrained at fixed offsets, but whose internal - * slot boundaries have a range of possible positions. - */ - - if (layoutPtr[start].minOffset == layoutPtr[start].maxOffset) { - start++; - continue; - } - - for (end=start+1; end<gridCount; end++) { - if (layoutPtr[end].minOffset == layoutPtr[end].maxOffset) { - break; - } - } - - /* - * We found a span. Compute the total weight, minumum space required, - * for this span, and the actual amount of space the span should - * use. - */ - - for (slot=start; slot<=end; slot++) { - totalWeight += layoutPtr[slot].weight; - need += layoutPtr[slot].minSize; - } - have = layoutPtr[end].maxOffset - layoutPtr[start-1].minOffset; - - /* - * If all the weights in the span are zero, then distribute the - * extra space evenly. - */ - - if (totalWeight == 0) { - noWeights++; - totalWeight = end - start + 1; - } - - /* - * It might not be possible to give the span all of the space - * available on this pass without violating the size constraints - * of one or more of the internal slot boundaries. - * Determine the maximum amount of space that when added to the - * entire span, would cause a slot boundary to have its possible - * range reduced to one value, and reduce the amount of extra - * space allocated on this pass accordingly. - * - * The calculation is done cumulatively to avoid accumulating - * roundoff errors. - */ - - for (weight=0,slot=start; slot<end; slot++) { - int diff = layoutPtr[slot].maxOffset - layoutPtr[slot].minOffset; - weight += noWeights ? 1 : layoutPtr[slot].weight; - if ((noWeights || layoutPtr[slot].weight>0) && - (diff*totalWeight/weight) < (have-need)) { - have = diff * totalWeight / weight + need; - } - } - - /* - * Now distribute the extra space among the slots by - * adjusting the minSizes and minOffsets. - */ - - for (weight=0,slot=start; slot<end; slot++) { - weight += noWeights ? 1 : layoutPtr[slot].weight; - layoutPtr[slot].minOffset += - (int)((double) (have-need) * weight/totalWeight + 0.5); - layoutPtr[slot].minSize = layoutPtr[slot].minOffset - - layoutPtr[slot-1].minOffset; - } - layoutPtr[slot].minSize = layoutPtr[slot].minOffset - - layoutPtr[slot-1].minOffset; - - /* - * Having pushed the top/left boundaries of the slots to - * take up extra space, the bottom/right space is recalculated - * to propagate the new space allocation. - */ - - for (slot=end; slot > start; slot--) { - layoutPtr[slot-1].maxOffset = - layoutPtr[slot].maxOffset-layoutPtr[slot].minSize; - } - } - - - /* - * Step 6. - * All of the space has been apportioned; copy the - * layout information back into the master. - */ - - for (slot=0; slot < gridCount; slot++) { - slotPtr[slot].offset = layoutPtr[slot].minOffset; - } - - --layoutPtr; - if (layoutPtr != layoutData) { - Tcl_Free((char *)layoutPtr); - } - return requiredSize; -} - -/* - *-------------------------------------------------------------- - * - * GetGrid -- - * - * This internal procedure is used to locate a Grid - * structure for a given window, creating one if one - * doesn't exist already. - * - * Results: - * The return value is a pointer to the Grid structure - * corresponding to tkwin. - * - * Side effects: - * A new grid structure may be created. If so, then - * a callback is set up to clean things up when the - * window is deleted. - * - *-------------------------------------------------------------- - */ - -static Gridder * -GetGrid(tkwin) - Tk_Window tkwin; /* Token for window for which - * grid structure is desired. */ -{ - register Gridder *gridPtr; - Tcl_HashEntry *hPtr; - int new; - - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&gridHashTable, TCL_ONE_WORD_KEYS); - } - - /* - * See if there's already grid for this window. If not, - * then create a new one. - */ - - hPtr = Tcl_CreateHashEntry(&gridHashTable, (char *) tkwin, &new); - if (!new) { - return (Gridder *) Tcl_GetHashValue(hPtr); - } - gridPtr = (Gridder *) Tcl_Alloc(sizeof(Gridder)); - gridPtr->tkwin = tkwin; - gridPtr->masterPtr = NULL; - gridPtr->masterDataPtr = NULL; - gridPtr->nextPtr = NULL; - gridPtr->slavePtr = NULL; - gridPtr->binNextPtr = NULL; - - gridPtr->column = gridPtr->row = -1; - gridPtr->numCols = 1; - gridPtr->numRows = 1; - - gridPtr->padX = gridPtr->padY = 0; - gridPtr->iPadX = gridPtr->iPadY = 0; - gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width; - gridPtr->abortPtr = NULL; - gridPtr->flags = 0; - gridPtr->sticky = 0; - gridPtr->size = 0; - gridPtr->masterDataPtr = NULL; - Tcl_SetHashValue(hPtr, gridPtr); - Tk_CreateEventHandler(tkwin, StructureNotifyMask, - GridStructureProc, (ClientData) gridPtr); - return gridPtr; -} - -/* - *-------------------------------------------------------------- - * - * SetGridSize -- - * - * This internal procedure sets the size of the grid occupied - * by slaves. - * - * Results: - * none - * - * Side effects: - * The width and height arguments are filled in the master data structure. - * Additional space is allocated for the constraints to accomodate - * the offsets. - * - *-------------------------------------------------------------- - */ - -static void -SetGridSize(masterPtr) - Gridder *masterPtr; /* The geometry master for this grid. */ -{ - register Gridder *slavePtr; /* Current slave window. */ - int maxX = 0, maxY = 0; - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - maxX = MAX(maxX,slavePtr->numCols + slavePtr->column); - maxY = MAX(maxY,slavePtr->numRows + slavePtr->row); - } - masterPtr->masterDataPtr->columnEnd = maxX; - masterPtr->masterDataPtr->rowEnd = maxY; - CheckSlotData(masterPtr, maxX, COLUMN, CHECK_SPACE); - CheckSlotData(masterPtr, maxY, ROW, CHECK_SPACE); -} - -/* - *-------------------------------------------------------------- - * - * CheckSlotData -- - * - * This internal procedure is used to manage the storage for - * row and column (slot) constraints. - * - * Results: - * TRUE if the index is OK, False otherwise. - * - * Side effects: - * A new master grid structure may be created. If so, then - * it is initialized. In addition, additional storage for - * a row or column constraints may be allocated, and the constraint - * maximums are adjusted. - * - *-------------------------------------------------------------- - */ - -static int -CheckSlotData(masterPtr, slot, slotType, checkOnly) - Gridder *masterPtr; /* the geometry master for this grid */ - int slot; /* which slot to look at */ - int slotType; /* ROW or COLUMN */ - int checkOnly; /* don't allocate new space if true */ -{ - int numSlot; /* number of slots already allocated (Space) */ - int end; /* last used constraint */ - - /* - * If slot is out of bounds, return immediately. - */ - - if (slot < 0 || slot >= MAX_ELEMENT) { - return TCL_ERROR; - } - - if ((checkOnly == CHECK_ONLY) && (masterPtr->masterDataPtr == NULL)) { - return TCL_ERROR; - } - - /* - * If we need to allocate more space, allocate a little extra to avoid - * repeated re-alloc's for large tables. We need enough space to - * hold all of the offsets as well. - */ - - InitMasterData(masterPtr); - end = (slotType == ROW) ? masterPtr->masterDataPtr->rowMax : - masterPtr->masterDataPtr->columnMax; - if (checkOnly == CHECK_ONLY) { - return (end < slot) ? TCL_ERROR : TCL_OK; - } else { - numSlot = (slotType == ROW) ? masterPtr->masterDataPtr->rowSpace - : masterPtr->masterDataPtr->columnSpace; - if (slot >= numSlot) { - int newNumSlot = slot + PREALLOC ; - size_t oldSize = numSlot * sizeof(SlotInfo) ; - size_t newSize = newNumSlot * sizeof(SlotInfo) ; - SlotInfo *new = (SlotInfo *) Tcl_Alloc(newSize); - SlotInfo *old = (slotType == ROW) ? - masterPtr->masterDataPtr->rowPtr : - masterPtr->masterDataPtr->columnPtr; - memcpy((VOID *) new, (VOID *) old, oldSize ); - memset((VOID *) (new+numSlot), 0, newSize - oldSize ); - Tcl_Free((char *) old); - if (slotType == ROW) { - masterPtr->masterDataPtr->rowPtr = new ; - masterPtr->masterDataPtr->rowSpace = newNumSlot ; - } else { - masterPtr->masterDataPtr->columnPtr = new; - masterPtr->masterDataPtr->columnSpace = newNumSlot ; - } - } - if (slot >= end && checkOnly != CHECK_SPACE) { - if (slotType == ROW) { - masterPtr->masterDataPtr->rowMax = slot+1; - } else { - masterPtr->masterDataPtr->columnMax = slot+1; - } - } - return TCL_OK; - } -} - -/* - *-------------------------------------------------------------- - * - * InitMasterData -- - * - * This internal procedure is used to allocate and initialize - * the data for a geometry master, if the data - * doesn't exist already. - * - * Results: - * none - * - * Side effects: - * A new master grid structure may be created. If so, then - * it is initialized. - * - *-------------------------------------------------------------- - */ - -static void -InitMasterData(masterPtr) - Gridder *masterPtr; -{ - size_t size; - if (masterPtr->masterDataPtr == NULL) { - GridMaster *gridPtr = masterPtr->masterDataPtr = - (GridMaster *) Tcl_Alloc(sizeof(GridMaster)); - size = sizeof(SlotInfo) * TYPICAL_SIZE; - - gridPtr->columnEnd = 0; - gridPtr->columnMax = 0; - gridPtr->columnPtr = (SlotInfo *) Tcl_Alloc(size); - gridPtr->columnSpace = 0; - gridPtr->columnSpace = TYPICAL_SIZE; - gridPtr->rowEnd = 0; - gridPtr->rowMax = 0; - gridPtr->rowPtr = (SlotInfo *) Tcl_Alloc(size); - gridPtr->rowSpace = 0; - gridPtr->rowSpace = TYPICAL_SIZE; - - memset((VOID *) gridPtr->columnPtr, 0, size); - memset((VOID *) gridPtr->rowPtr, 0, size); - } -} - -/* - *---------------------------------------------------------------------- - * - * Unlink -- - * - * Remove a grid from its parent's list of slaves. - * - * Results: - * None. - * - * Side effects: - * The parent will be scheduled for re-arranging, and the size of the - * grid will be adjusted accordingly - * - *---------------------------------------------------------------------- - */ - -static void -Unlink(slavePtr) - register Gridder *slavePtr; /* Window to unlink. */ -{ - register Gridder *masterPtr, *slavePtr2; - GridMaster *gridPtr; /* pointer to grid data */ - - masterPtr = slavePtr->masterPtr; - if (masterPtr == NULL) { - return; - } - - gridPtr = masterPtr->masterDataPtr; - if (masterPtr->slavePtr == slavePtr) { - masterPtr->slavePtr = slavePtr->nextPtr; - } - else { - for (slavePtr2 = masterPtr->slavePtr; ; slavePtr2 = slavePtr2->nextPtr) { - if (slavePtr2 == NULL) { - panic("Unlink couldn't find previous window"); - } - if (slavePtr2->nextPtr == slavePtr) { - slavePtr2->nextPtr = slavePtr->nextPtr; - break; - } - } - } - if (!(masterPtr->flags & REQUESTED_RELAYOUT)) { - masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr); - } - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - - if ((slavePtr->numCols+slavePtr->column == gridPtr->columnMax) - || (slavePtr->numRows+slavePtr->row == gridPtr->rowMax)) { - } - slavePtr->masterPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyGrid -- - * - * This procedure is invoked by Tk_EventuallyFree or Tcl_Release - * to clean up the internal structure of a grid at a safe time - * (when no-one is using it anymore). Cleaning up the grid involves - * freeing the main structure for all windows. and the master structure - * for geometry managers. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the grid is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyGrid(memPtr) - char *memPtr; /* Info about window that is now dead. */ -{ - register Gridder *gridPtr = (Gridder *) memPtr; - - if (gridPtr->masterDataPtr != NULL) { - if (gridPtr->masterDataPtr->rowPtr != NULL) { - Tcl_Free((char *) gridPtr->masterDataPtr -> rowPtr); - } - if (gridPtr->masterDataPtr->columnPtr != NULL) { - Tcl_Free((char *) gridPtr->masterDataPtr -> columnPtr); - } - Tcl_Free((char *) gridPtr->masterDataPtr); - } - Tcl_Free((char *) gridPtr); -} - -/* - *---------------------------------------------------------------------- - * - * GridStructureProc -- - * - * This procedure is invoked by the Tk event dispatcher in response - * to StructureNotify events. - * - * Results: - * None. - * - * Side effects: - * If a window was just deleted, clean up all its grid-related - * information. If it was just resized, re-configure its slaves, if - * any. - * - *---------------------------------------------------------------------- - */ - -static void -GridStructureProc(clientData, eventPtr) - ClientData clientData; /* Our information about window - * referred to by eventPtr. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - register Gridder *gridPtr = (Gridder *) clientData; - - if (eventPtr->type == ConfigureNotify) { - if (!(gridPtr->flags & REQUESTED_RELAYOUT)) { - gridPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr); - } - if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) { - if ((gridPtr->masterPtr != NULL) && - !(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) { - gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width; - gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr); - } - } - } else if (eventPtr->type == DestroyNotify) { - register Gridder *gridPtr2, *nextPtr; - - if (gridPtr->masterPtr != NULL) { - Unlink(gridPtr); - } - for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL; - gridPtr2 = nextPtr) { - Tk_UnmapWindow(gridPtr2->tkwin); - gridPtr2->masterPtr = NULL; - nextPtr = gridPtr2->nextPtr; - gridPtr2->nextPtr = NULL; - } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&gridHashTable, - (char *) gridPtr->tkwin)); - if (gridPtr->flags & REQUESTED_RELAYOUT) { - Tk_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr); - } - gridPtr->tkwin = NULL; - Tk_EventuallyFree((ClientData) gridPtr, DestroyGrid); - } else if (eventPtr->type == MapNotify) { - if (!(gridPtr->flags & REQUESTED_RELAYOUT)) { - gridPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr); - } - } else if (eventPtr->type == UnmapNotify) { - register Gridder *gridPtr2; - - for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL; - gridPtr2 = gridPtr2->nextPtr) { - Tk_UnmapWindow(gridPtr2->tkwin); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureSlaves -- - * - * This implements the guts of the "grid configure" command. Given - * a list of slaves and configuration options, it arranges for the - * grid to manage the slaves and sets the specified options. - * arguments consist of windows or window shortcuts followed by - * "-option value" pairs. - * - * Results: - * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is - * returned and interp->result is set to contain an error message. - * - * Side effects: - * Slave windows get taken over by the grid. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureSlaves(interp, tkwin, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Any window in application containing - * slaves. Used to look up slave names. */ - int argc; /* Number of elements in argv. */ - char *argv[]; /* Argument strings: contains one or more - * window names followed by any number - * of "option value" pairs. Caller must - * make sure that there is at least one - * window name. */ -{ - Gridder *masterPtr; - Gridder *slavePtr; - Tk_Window other, slave, parent, ancestor; - int i, j, c, tmp; - size_t length; - int numWindows; - int width; - int defaultColumn = 0; /* default column number */ - int defaultColumnSpan = 1; /* default number of columns */ - char *lastWindow; /* use this window to base current - * Row/col on */ - - /* - * Count the number of windows, or window short-cuts. - */ - - for(numWindows=i=0;i<argc;i++) { - char firstChar = *argv[i]; - if (firstChar == '.') { - numWindows++; - continue; - } - length = strlen(argv[i]); - if (length > 1 && firstChar == '-') { - break; - } - if (length > 1) { - Tcl_AppendResult(interp, "unexpected parameter, \"", - argv[i], "\", in configure list. ", - "Should be window name or option", (char *) NULL); - return TCL_ERROR; - } - - if ((firstChar == REL_HORIZ) && ((numWindows == 0) || - (*argv[i-1] == REL_SKIP) || (*argv[i-1] == REL_VERT))) { - Tcl_AppendResult(interp, - "Must specify window before shortcut '-'.", - (char *) NULL); - return TCL_ERROR; - } - - if ((firstChar == REL_VERT) || (firstChar == REL_SKIP) - || (firstChar == REL_HORIZ)) { - continue; - } - - Tcl_AppendResult(interp, "invalid window shortcut, \"", - argv[i], "\" should be '-', 'x', or '^'", (char *) NULL); - return TCL_ERROR; - } - numWindows = i; - - if ((argc-numWindows)&1) { - Tcl_AppendResult(interp, "extra option or", - " option with no value", (char *) NULL); - return TCL_ERROR; - } - - /* - * Iterate over all of the slave windows and short-cuts, parsing - * options for each slave. It's a bit wasteful to re-parse the - * options for each slave, but things get too messy if we try to - * parse the arguments just once at the beginning. For example, - * if a slave already is managed we want to just change a few - * existing values without resetting everything. If there are - * multiple windows, the -in option only gets processed for the - * first window. - */ - - masterPtr = NULL; - for (j = 0; j < numWindows; j++) { - char firstChar = *argv[j]; - - /* - * '^' and 'x' cause us to skip a column. '-' is processed - * as part of its preceeding slave. - */ - - if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)) { - defaultColumn++; - continue; - } - if (firstChar == REL_HORIZ) { - continue; - } - - for (defaultColumnSpan=1; - j + defaultColumnSpan < numWindows && - (*argv[j+defaultColumnSpan] == REL_HORIZ); - defaultColumnSpan++) { - /* null body */ - } - - slave = Tk_NameToWindow(interp, argv[j], tkwin); - if (slave == NULL) { - return TCL_ERROR; - } - if (Tk_IsTopLevel(slave)) { - Tcl_AppendResult(interp, "can't manage \"", argv[j], - "\": it's a top-level window", (char *) NULL); - return TCL_ERROR; - } - slavePtr = GetGrid(slave); - - /* - * The following statement is taken from tkPack.c: - * - * "If the slave isn't currently managed, reset all of its - * configuration information to default values (there could - * be old values left from a previous packer)." - * - * I [D.S.] disagree with this statement. If a slave is disabled (using - * "forget") and then re-enabled, I submit that 90% of the time the - * programmer will want it to retain its old configuration information. - * If the programmer doesn't want this behavior, then the - * defaults can be reestablished by hand, without having to worry - * about keeping track of the old state. - */ - - for (i = numWindows; i < argc; i+=2) { - length = strlen(argv[i]); - c = argv[i][1]; - - if (length < 2) { - Tcl_AppendResult(interp, "unknown or ambiguous option \"", - argv[i], "\": must be ", - "-column, -columnspan, -in, -ipadx, -ipady, ", - "-padx, -pady, -row, -rowspan, or -sticky", - (char *) NULL); - return TCL_ERROR; - } - if ((c == 'c') && (strncmp(argv[i], "-column", length) == 0)) { - if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad column value \"", argv[i+1], - "\": must be a non-negative integer", (char *)NULL); - return TCL_ERROR; - } - slavePtr->column = tmp; - } else if ((c == 'c') - && (strncmp(argv[i], "-columnspan", length) == 0)) { - if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1], - "\": must be a positive integer", (char *)NULL); - return TCL_ERROR; - } - slavePtr->numCols = tmp; - } else if ((c == 'i') && (strncmp(argv[i], "-in", length) == 0)) { - other = Tk_NameToWindow(interp, argv[i+1], tkwin); - if (other == NULL) { - return TCL_ERROR; - } - if (other == slave) { - sprintf(interp->result,"Window can't be managed in itself"); - return TCL_ERROR; - } - masterPtr = GetGrid(other); - InitMasterData(masterPtr); - } else if ((c == 'i') - && (strncmp(argv[i], "-ipadx", length) == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp < 0)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1], - "\": must be positive screen distance", - (char *) NULL); - return TCL_ERROR; - } - slavePtr->iPadX = tmp*2; - } else if ((c == 'i') - && (strncmp(argv[i], "-ipady", length) == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1], - "\": must be positive screen distance", - (char *) NULL); - return TCL_ERROR; - } - slavePtr->iPadY = tmp*2; - } else if ((c == 'p') - && (strncmp(argv[i], "-padx", length) == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad padx value \"", argv[i+1], - "\": must be positive screen distance", - (char *) NULL); - return TCL_ERROR; - } - slavePtr->padX = tmp*2; - } else if ((c == 'p') - && (strncmp(argv[i], "-pady", length) == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad pady value \"", argv[i+1], - "\": must be positive screen distance", - (char *) NULL); - return TCL_ERROR; - } - slavePtr->padY = tmp*2; - } else if ((c == 'r') && (strncmp(argv[i], "-row", length) == 0)) { - if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad grid value \"", argv[i+1], - "\": must be a non-negative integer", (char *)NULL); - return TCL_ERROR; - } - slavePtr->row = tmp; - } else if ((c == 'r') - && (strncmp(argv[i], "-rowspan", length) == 0)) { - if ((Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) || tmp<=0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1], - "\": must be a positive integer", (char *)NULL); - return TCL_ERROR; - } - slavePtr->numRows = tmp; - } else if ((c == 's') - && strncmp(argv[i], "-sticky", length) == 0) { - int sticky = StringToSticky(argv[i+1]); - if (sticky == -1) { - Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1], - "\": must be a string containing n, e, s, and/or w", - (char *)NULL); - return TCL_ERROR; - } - slavePtr->sticky = sticky; - } else { - Tcl_AppendResult(interp, "unknown or ambiguous option \"", - argv[i], "\": must be ", - "-column, -columnspan, -in, -ipadx, -ipady, ", - "-padx, -pady, -row, -rowspan, or -sticky", - (char *) NULL); - return TCL_ERROR; - } - } - - /* - * Make sure we have a geometry master. We look at: - * 1) the -in flag - * 2) the geometry master of the first slave (if specified) - * 3) the parent of the first slave. - */ - - if (masterPtr == NULL) { - masterPtr = slavePtr->masterPtr; - } - parent = Tk_Parent(slave); - if (masterPtr == NULL) { - masterPtr = GetGrid(parent); - InitMasterData(masterPtr); - } - - if (slavePtr->masterPtr != NULL && slavePtr->masterPtr != masterPtr) { - Unlink(slavePtr); - slavePtr->masterPtr = NULL; - } - - if (slavePtr->masterPtr == NULL) { - Gridder *tempPtr = masterPtr->slavePtr; - slavePtr->masterPtr = masterPtr; - masterPtr->slavePtr = slavePtr; - slavePtr->nextPtr = tempPtr; - } - - /* - * Make sure that the slave's parent is either the master or - * an ancestor of the master, and that the master and slave - * aren't the same. - */ - - for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { - if (ancestor == parent) { - break; - } - if (Tk_IsTopLevel(ancestor)) { - Tcl_AppendResult(interp, "can't put ", argv[j], - " inside ", Tk_PathName(masterPtr->tkwin), - (char *) NULL); - Unlink(slavePtr); - return TCL_ERROR; - } - } - - /* - * Try to make sure our master isn't managed by us. - */ - - if (masterPtr->masterPtr == slavePtr) { - Tcl_AppendResult(interp, "can't put ", argv[j], - " inside ", Tk_PathName(masterPtr->tkwin), - ", would cause management loop.", - (char *) NULL); - Unlink(slavePtr); - return TCL_ERROR; - } - - Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr); - - /* - * Assign default position information. - */ - - if (slavePtr->column == -1) { - slavePtr->column = defaultColumn; - } - slavePtr->numCols += defaultColumnSpan - 1; - if (slavePtr->row == -1) { - if (masterPtr->masterDataPtr == NULL) { - slavePtr->row = 0; - } else { - slavePtr->row = masterPtr->masterDataPtr->rowEnd; - } - } - defaultColumn += slavePtr->numCols; - defaultColumnSpan = 1; - - /* - * Arrange for the parent to be re-arranged at the first - * idle moment. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_RELAYOUT)) { - masterPtr->flags |= REQUESTED_RELAYOUT; - Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr); - } - } - - /* Now look for all the "^"'s. */ - - lastWindow = NULL; - for (j = 0; j < numWindows; j++) { - struct Gridder *otherPtr; - int match; /* found a match for the ^ */ - int lastRow, lastColumn; /* implied end of table */ - - if (*argv[j] == '.') { - lastWindow = argv[j]; - } - if (*argv[j] != REL_VERT) { - continue; - } - - if (masterPtr == NULL) { - Tcl_AppendResult(interp, "can't use '^', cant find master", - (char *) NULL); - return TCL_ERROR; - } - - for (width=1; width+j < numWindows && *argv[j+width] == REL_VERT; - width++) { - /* Null Body */ - } - - /* - * Find the implied grid location of the ^ - */ - - if (lastWindow == NULL) { - if (masterPtr->masterDataPtr != NULL) { - SetGridSize(masterPtr); - lastRow = masterPtr->masterDataPtr->rowEnd - 1; - } else { - lastRow = 0; - } - lastColumn = 0; - } else { - other = Tk_NameToWindow(interp, lastWindow, tkwin); - otherPtr = GetGrid(other); - lastRow = otherPtr->row; - lastColumn = otherPtr->column + otherPtr->numCols; - } - - for (match=0, slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - - if (slavePtr->numCols == width - && slavePtr->column == lastColumn - && slavePtr->row + slavePtr->numRows == lastRow) { - slavePtr->numRows++; - match++; - } - lastWindow = Tk_PathName(slavePtr->tkwin); - } - if (!match) { - Tcl_AppendResult(interp, "can't find slave to extend with \"^\".", - (char *) NULL); - return TCL_ERROR; - } - j += width - 1; - } - - if (masterPtr == NULL) { - Tcl_AppendResult(interp, "can't determine master window", - (char *) NULL); - return TCL_ERROR; - } - SetGridSize(masterPtr); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * StickyToString - * - * Converts the internal boolean combination of "sticky" bits onto - * a TCL list element containing zero or mor of n, s, e, or w. - * - * Results: - * A string is placed into the "result" pointer. - * - * Side effects: - * none. - * - *---------------------------------------------------------------------- - */ - -static void -StickyToString(flags, result) - int flags; /* the sticky flags */ - char *result; /* where to put the result */ -{ - int count = 0; - if (flags&STICK_NORTH) { - result[count++] = 'n'; - } - if (flags&STICK_EAST) { - result[count++] = 'e'; - } - if (flags&STICK_SOUTH) { - result[count++] = 's'; - } - if (flags&STICK_WEST) { - result[count++] = 'w'; - } - if (count) { - result[count] = '\0'; - } else { - sprintf(result,"{}"); - } -} - -/* - *---------------------------------------------------------------------- - * - * StringToSticky -- - * - * Converts an ascii string representing a widgets stickyness - * into the boolean result. - * - * Results: - * The boolean combination of the "sticky" bits is retuned. If an - * error occurs, such as an invalid character, -1 is returned instead. - * - * Side effects: - * none - * - *---------------------------------------------------------------------- - */ - -static int -StringToSticky(string) - char *string; -{ - int sticky = 0; - char c; - - while ((c = *string++) != '\0') { - switch (c) { - case 'n': case 'N': sticky |= STICK_NORTH; break; - case 'e': case 'E': sticky |= STICK_EAST; break; - case 's': case 'S': sticky |= STICK_SOUTH; break; - case 'w': case 'W': sticky |= STICK_WEST; break; - case ' ': case ',': case '\t': case '\r': case '\n': break; - default: return -1; - } - } - return sticky; -} diff --git a/generic/tkImage.c b/generic/tkImage.c deleted file mode 100644 index d2733ba..0000000 --- a/generic/tkImage.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * tkImage.c -- - * - * This module implements the image protocol, which allows lots - * of different kinds of images to be used in lots of different - * widgets. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkImage.c,v 1.2 1998/09/14 18:23:12 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - * Each call to Tk_GetImage returns a pointer to one of the following - * structures, which is used as a token by clients (widgets) that - * display images. - */ - -typedef struct Image { - Tk_Window tkwin; /* Window passed to Tk_GetImage (needed to - * "re-get" the image later if the manager - * changes). */ - Display *display; /* Display for tkwin. Needed because when - * the image is eventually freed tkwin may - * not exist anymore. */ - struct ImageMaster *masterPtr; - /* Master for this image (identifiers image - * manager, for example). */ - ClientData instanceData; - /* One word argument to pass to image manager - * when dealing with this image instance. */ - Tk_ImageChangedProc *changeProc; - /* Code in widget to call when image changes - * in a way that affects redisplay. */ - ClientData widgetClientData; - /* Argument to pass to changeProc. */ - struct Image *nextPtr; /* Next in list of all image instances - * associated with the same name. */ - -} Image; - -/* - * For each image master there is one of the following structures, - * which represents a name in the image table and all of the images - * instantiated from it. Entries in mainPtr->imageTable point to - * these structures. - */ - -typedef struct ImageMaster { - Tk_ImageType *typePtr; /* Information about image type. NULL means - * that no image manager owns this image: the - * image was deleted. */ - ClientData masterData; /* One-word argument to pass to image mgr - * when dealing with the master, as opposed - * to instances. */ - int width, height; /* Last known dimensions for image. */ - Tcl_HashTable *tablePtr; /* Pointer to hash table containing image - * (the imageTable field in some TkMainInfo - * structure). */ - Tcl_HashEntry *hPtr; /* Hash entry in mainPtr->imageTable for - * this structure (used to delete the hash - * entry). */ - Image *instancePtr; /* Pointer to first in list of instances - * derived from this name. */ -} ImageMaster; - -/* - * The following variable points to the first in a list of all known - * image types. - */ - -static Tk_ImageType *imageTypeList = NULL; - -/* - * Prototypes for local procedures: - */ - -static void DeleteImage _ANSI_ARGS_((ImageMaster *masterPtr)); - -/* - *---------------------------------------------------------------------- - * - * Tk_CreateImageType -- - * - * This procedure is invoked by an image manager to tell Tk about - * a new kind of image and the procedures that manage the new type. - * The procedure is typically invoked during Tcl_AppInit. - * - * Results: - * None. - * - * Side effects: - * The new image type is entered into a table used in the "image - * create" command. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CreateImageType(typePtr) - Tk_ImageType *typePtr; /* Structure describing the type. All of - * the fields except "nextPtr" must be filled - * in by caller. Must not have been passed - * to Tk_CreateImageType previously. */ -{ - typePtr->nextPtr = imageTypeList; - imageTypeList = typePtr; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ImageCmd -- - * - * This procedure is invoked to process the "image" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -int -Tk_ImageCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr = (TkWindow *) clientData; - int c, i, new, firstOption; - size_t length; - Tk_ImageType *typePtr; - ImageMaster *masterPtr; - Image *imagePtr; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - char idString[30], *name; - static int id = 0; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?args?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " create type ?name? ?options?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[2][0]; - - /* - * Look up the image type. - */ - - for (typePtr = imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - if ((c == typePtr->name[0]) - && (strcmp(argv[2], typePtr->name) == 0)) { - break; - } - } - if (typePtr == NULL) { - Tcl_AppendResult(interp, "image type \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - - /* - * Figure out a name to use for the new image. - */ - - if ((argc == 3) || (argv[3][0] == '-')) { - id++; - sprintf(idString, "image%d", id); - name = idString; - firstOption = 3; - } else { - name = argv[3]; - firstOption = 4; - } - - /* - * Create the data structure for the new image. - */ - - hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, name, &new); - if (new) { - masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); - masterPtr->typePtr = NULL; - masterPtr->masterData = NULL; - masterPtr->width = masterPtr->height = 1; - masterPtr->tablePtr = &winPtr->mainPtr->imageTable; - masterPtr->hPtr = hPtr; - masterPtr->instancePtr = NULL; - Tcl_SetHashValue(hPtr, masterPtr); - } else { - /* - * An image already exists by this name. Disconnect the - * instances from the master. - */ - - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - (*masterPtr->typePtr->freeProc)( - imagePtr->instanceData, imagePtr->display); - (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0, - masterPtr->width, masterPtr->height, masterPtr->width, - masterPtr->height); - } - (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); - masterPtr->typePtr = NULL; - } - } - - /* - * Call the image type manager so that it can perform its own - * initialization, then re-"get" for any existing instances of - * the image. - */ - - if ((*typePtr->createProc)(interp, name, argc-firstOption, - argv+firstOption, typePtr, (Tk_ImageMaster) masterPtr, - &masterPtr->masterData) != TCL_OK) { - DeleteImage(masterPtr); - return TCL_ERROR; - } - masterPtr->typePtr = typePtr; - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - imagePtr->instanceData = (*typePtr->getProc)( - imagePtr->tkwin, masterPtr->masterData); - } - interp->result = Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr); - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - for (i = 2; i < argc; i++) { - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[i]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[i], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - DeleteImage(masterPtr); - } - } else if ((c == 'h') && (strncmp(argv[1], "height", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " height name\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - sprintf(interp->result, "%d", masterPtr->height); - } else if ((c == 'n') && (strncmp(argv[1], "names", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " names\"", (char *) NULL); - return TCL_ERROR; - } - for (hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, Tcl_GetHashKey( - &winPtr->mainPtr->imageTable, hPtr)); - } - } else if ((c == 't') && (strcmp(argv[1], "type") == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " type name\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - interp->result = masterPtr->typePtr->name; - } - } else if ((c == 't') && (strcmp(argv[1], "types") == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " types\"", (char *) NULL); - return TCL_ERROR; - } - for (typePtr = imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - Tcl_AppendElement(interp, typePtr->name); - } - } else if ((c == 'w') && (strncmp(argv[1], "width", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " width name\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - sprintf(interp->result, "%d", masterPtr->width); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be create, delete, height, names, type, types,", - " or width", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ImageChanged -- - * - * This procedure is called by an image manager whenever something - * has happened that requires the image to be redrawn (some of its - * pixels have changed, or its size has changed). - * - * Results: - * None. - * - * Side effects: - * Any widgets that display the image are notified so that they - * can redisplay themselves as appropriate. - * - *---------------------------------------------------------------------- - */ - -void -Tk_ImageChanged(imageMaster, x, y, width, height, imageWidth, - imageHeight) - Tk_ImageMaster imageMaster; /* Image that needs redisplay. */ - int x, y; /* Coordinates of upper-left pixel of - * region of image that needs to be - * redrawn. */ - int width, height; /* Dimensions (in pixels) of region of - * image to redraw. If either dimension - * is zero then the image doesn't need to - * be redrawn (perhaps all that happened is - * that its size changed). */ - int imageWidth, imageHeight;/* New dimensions of image. */ -{ - ImageMaster *masterPtr = (ImageMaster *) imageMaster; - Image *imagePtr; - - masterPtr->width = imageWidth; - masterPtr->height = imageHeight; - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - (*imagePtr->changeProc)(imagePtr->widgetClientData, x, y, - width, height, imageWidth, imageHeight); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_NameOfImage -- - * - * Given a token for an image master, this procedure returns - * the name of the image. - * - * Results: - * The return value is the string name for imageMaster. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -Tk_NameOfImage(imageMaster) - Tk_ImageMaster imageMaster; /* Token for image. */ -{ - ImageMaster *masterPtr = (ImageMaster *) imageMaster; - - return Tcl_GetHashKey(masterPtr->tablePtr, masterPtr->hPtr); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetImage -- - * - * This procedure is invoked by a widget when it wants to use - * a particular image in a particular window. - * - * Results: - * The return value is a token for the image. If there is no image - * by the given name, then NULL is returned and an error message is - * left in interp->result. - * - * Side effects: - * Tk records the fact that the widget is using the image, and - * it will invoke changeProc later if the widget needs redisplay - * (i.e. its size changes or some of its pixels change). The - * caller must eventually invoke Tk_FreeImage when it no longer - * needs the image. - * - *---------------------------------------------------------------------- - */ - -Tk_Image -Tk_GetImage(interp, tkwin, name, changeProc, clientData) - Tcl_Interp *interp; /* Place to leave error message if image - * can't be found. */ - Tk_Window tkwin; /* Token for window in which image will - * be used. */ - char *name; /* Name of desired image. */ - Tk_ImageChangedProc *changeProc; - /* Procedure to invoke when redisplay is - * needed because image's pixels or size - * changed. */ - ClientData clientData; /* One-word argument to pass to damageProc. */ -{ - Tcl_HashEntry *hPtr; - ImageMaster *masterPtr; - Image *imagePtr; - - hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->imageTable, name); - if (hPtr == NULL) { - goto noSuchImage; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr == NULL) { - goto noSuchImage; - } - imagePtr = (Image *) ckalloc(sizeof(Image)); - imagePtr->tkwin = tkwin; - imagePtr->display = Tk_Display(tkwin); - imagePtr->masterPtr = masterPtr; - imagePtr->instanceData = - (*masterPtr->typePtr->getProc)(tkwin, masterPtr->masterData); - imagePtr->changeProc = changeProc; - imagePtr->widgetClientData = clientData; - imagePtr->nextPtr = masterPtr->instancePtr; - masterPtr->instancePtr = imagePtr; - return (Tk_Image) imagePtr; - - noSuchImage: - Tcl_AppendResult(interp, "image \"", name, "\" doesn't exist", - (char *) NULL); - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeImage -- - * - * This procedure is invoked by a widget when it no longer needs - * an image acquired by a previous call to Tk_GetImage. For each - * call to Tk_GetImage there must be exactly one call to Tk_FreeImage. - * - * Results: - * None. - * - * Side effects: - * The association between the image and the widget is removed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeImage(image) - Tk_Image image; /* Token for image that is no longer - * needed by a widget. */ -{ - Image *imagePtr = (Image *) image; - ImageMaster *masterPtr = imagePtr->masterPtr; - Image *prevPtr; - - /* - * Clean up the particular instance. - */ - - if (masterPtr->typePtr != NULL) { - (*masterPtr->typePtr->freeProc)(imagePtr->instanceData, - imagePtr->display); - } - prevPtr = masterPtr->instancePtr; - if (prevPtr == imagePtr) { - masterPtr->instancePtr = imagePtr->nextPtr; - } else { - while (prevPtr->nextPtr != imagePtr) { - prevPtr = prevPtr->nextPtr; - } - prevPtr->nextPtr = imagePtr->nextPtr; - } - ckfree((char *) imagePtr); - - /* - * If there are no more instances left for the master, and if the - * master image has been deleted, then delete the master too. - */ - - if ((masterPtr->typePtr == NULL) && (masterPtr->instancePtr == NULL)) { - Tcl_DeleteHashEntry(masterPtr->hPtr); - ckfree((char *) masterPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_RedrawImage -- - * - * This procedure is called by widgets that contain images in order - * to redisplay an image on the screen or an off-screen pixmap. - * - * Results: - * None. - * - * Side effects: - * The image's manager is notified, and it redraws the desired - * portion of the image before returning. - * - *---------------------------------------------------------------------- - */ - -void -Tk_RedrawImage(image, imageX, imageY, width, height, drawable, - drawableX, drawableY) - Tk_Image image; /* Token for image to redisplay. */ - int imageX, imageY; /* Upper-left pixel of region in image that - * needs to be redisplayed. */ - int width, height; /* Dimensions of region to redraw. */ - Drawable drawable; /* Drawable in which to display image - * (window or pixmap). If this is a pixmap, - * it must have the same depth as the window - * used in the Tk_GetImage call for the - * image. */ - int drawableX, drawableY; /* Coordinates in drawable that correspond - * to imageX and imageY. */ -{ - Image *imagePtr = (Image *) image; - - if (imagePtr->masterPtr->typePtr == NULL) { - /* - * No master for image, so nothing to display. - */ - - return; - } - - /* - * Clip the redraw area to the area of the image. - */ - - if (imageX < 0) { - width += imageX; - drawableX -= imageX; - imageX = 0; - } - if (imageY < 0) { - height += imageY; - drawableY -= imageY; - imageY = 0; - } - if ((imageX + width) > imagePtr->masterPtr->width) { - width = imagePtr->masterPtr->width - imageX; - } - if ((imageY + height) > imagePtr->masterPtr->height) { - height = imagePtr->masterPtr->height - imageY; - } - (*imagePtr->masterPtr->typePtr->displayProc)( - imagePtr->instanceData, imagePtr->display, drawable, - imageX, imageY, width, height, drawableX, drawableY); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SizeOfImage -- - * - * This procedure returns the current dimensions of an image. - * - * Results: - * The width and height of the image are returned in *widthPtr - * and *heightPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Tk_SizeOfImage(image, widthPtr, heightPtr) - Tk_Image image; /* Token for image whose size is wanted. */ - int *widthPtr; /* Return width of image here. */ - int *heightPtr; /* Return height of image here. */ -{ - Image *imagePtr = (Image *) image; - - *widthPtr = imagePtr->masterPtr->width; - *heightPtr = imagePtr->masterPtr->height; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DeleteImage -- - * - * Given the name of an image, this procedure destroys the - * image. - * - * Results: - * None. - * - * Side effects: - * The image is destroyed; existing instances will display as - * blank areas. If no such image exists then the procedure does - * nothing. - * - *---------------------------------------------------------------------- - */ - -void -Tk_DeleteImage(interp, name) - Tcl_Interp *interp; /* Interpreter in which the image was - * created. */ - char *name; /* Name of image. */ -{ - Tcl_HashEntry *hPtr; - TkWindow *winPtr; - - winPtr = (TkWindow *) Tk_MainWindow(interp); - if (winPtr == NULL) { - return; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); - if (hPtr == NULL) { - return; - } - DeleteImage((ImageMaster *) Tcl_GetHashValue(hPtr)); -} - -/* - *---------------------------------------------------------------------- - * - * DeleteImage -- - * - * This procedure is responsible for deleting an image. - * - * Results: - * None. - * - * Side effects: - * The connection is dropped between instances of this image and - * an image master. Image instances will redisplay themselves - * as empty areas, but existing instances will not be deleted. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteImage(masterPtr) - ImageMaster *masterPtr; /* Pointer to main data structure for image. */ -{ - Image *imagePtr; - Tk_ImageType *typePtr; - - typePtr = masterPtr->typePtr; - masterPtr->typePtr = NULL; - if (typePtr != NULL) { - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - (*typePtr->freeProc)(imagePtr->instanceData, - imagePtr->display); - (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0, - masterPtr->width, masterPtr->height, masterPtr->width, - masterPtr->height); - } - (*typePtr->deleteProc)(masterPtr->masterData); - } - if (masterPtr->instancePtr == NULL) { - Tcl_DeleteHashEntry(masterPtr->hPtr); - ckfree((char *) masterPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkDeleteAllImages -- - * - * This procedure is called when an application is deleted. It - * calls back all of the managers for all images so that they - * can cleanup, then it deletes all of Tk's internal information - * about images. - * - * Results: - * None. - * - * Side effects: - * All information for all images gets deleted. - * - *---------------------------------------------------------------------- - */ - -void -TkDeleteAllImages(mainPtr) - TkMainInfo *mainPtr; /* Structure describing application that is - * going away. */ -{ - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - ImageMaster *masterPtr; - - for (hPtr = Tcl_FirstHashEntry(&mainPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - DeleteImage(masterPtr); - } - Tcl_DeleteHashTable(&mainPtr->imageTable); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetImageMasterData -- - * - * Given the name of an image, this procedure returns the type - * of the image and the clientData associated with its master. - * - * Results: - * If there is no image by the given name, then NULL is returned - * and a NULL value is stored at *typePtrPtr. Otherwise the return - * value is the clientData returned by the createProc when the - * image was created and a pointer to the type structure for the - * image is stored at *typePtrPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -ClientData -Tk_GetImageMasterData(interp, name, typePtrPtr) - Tcl_Interp *interp; /* Interpreter in which the image was - * created. */ - char *name; /* Name of image. */ - Tk_ImageType **typePtrPtr; /* Points to location to fill in with - * pointer to type information for image. */ -{ - Tcl_HashEntry *hPtr; - TkWindow *winPtr; - ImageMaster *masterPtr; - - winPtr = (TkWindow *) Tk_MainWindow(interp); - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); - if (hPtr == NULL) { - *typePtrPtr = NULL; - return NULL; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - *typePtrPtr = masterPtr->typePtr; - return masterPtr->masterData; -} diff --git a/generic/tkImgBmap.c b/generic/tkImgBmap.c deleted file mode 100644 index d3e9f41..0000000 --- a/generic/tkImgBmap.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * tkImgBmap.c -- - * - * This procedure implements images of type "bitmap" for Tk. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkImgBmap.c,v 1.4 1998/09/14 18:23:12 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - * The following data structure represents the master for a bitmap - * image: - */ - -typedef struct BitmapMaster { - Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means - * the image is being deleted. */ - Tcl_Interp *interp; /* Interpreter for application that is - * using image. */ - Tcl_Command imageCmd; /* Token for image command (used to delete - * it when the image goes away). NULL means - * the image command has already been - * deleted. */ - int width, height; /* Dimensions of image. */ - char *data; /* Data comprising bitmap (suitable for - * input to XCreateBitmapFromData). May - * be NULL if no data. Malloc'ed. */ - char *maskData; /* Data for bitmap's mask (suitable for - * input to XCreateBitmapFromData). - * Malloc'ed. */ - Tk_Uid fgUid; /* Value of -foreground option (malloc'ed). */ - Tk_Uid bgUid; /* Value of -background option (malloc'ed). */ - char *fileString; /* Value of -file option (malloc'ed). */ - char *dataString; /* Value of -data option (malloc'ed). */ - char *maskFileString; /* Value of -maskfile option (malloc'ed). */ - char *maskDataString; /* Value of -maskdata option (malloc'ed). */ - struct BitmapInstance *instancePtr; - /* First in list of all instances associated - * with this master. */ -} BitmapMaster; - -/* - * The following data structure represents all of the instances of an - * image that lie within a particular window: - */ - -typedef struct BitmapInstance { - int refCount; /* Number of instances that share this - * data structure. */ - BitmapMaster *masterPtr; /* Pointer to master for image. */ - Tk_Window tkwin; /* Window in which the instances will be - * displayed. */ - XColor *fg; /* Foreground color for displaying image. */ - XColor *bg; /* Background color for displaying image. */ - Pixmap bitmap; /* The bitmap to display. */ - Pixmap mask; /* Mask: only display bitmap pixels where - * there are 1's here. */ - GC gc; /* Graphics context for displaying bitmap. - * None means there was an error while - * setting up the instance, so it cannot - * be displayed. */ - struct BitmapInstance *nextPtr; - /* Next in list of all instance structures - * associated with masterPtr (NULL means - * end of list). */ -} BitmapInstance; - -/* - * The type record for bitmap images: - */ - -static int GetByte _ANSI_ARGS_((Tcl_Channel chan)); -static int ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int argc, char **argv, - Tk_ImageType *typePtr, Tk_ImageMaster master, - ClientData *clientDataPtr)); -static ClientData ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin, - ClientData clientData)); -static void ImgBmapDisplay _ANSI_ARGS_((ClientData clientData, - Display *display, Drawable drawable, - int imageX, int imageY, int width, int height, - int drawableX, int drawableY)); -static void ImgBmapFree _ANSI_ARGS_((ClientData clientData, - Display *display)); -static void ImgBmapDelete _ANSI_ARGS_((ClientData clientData)); - -Tk_ImageType tkBitmapImageType = { - "bitmap", /* name */ - ImgBmapCreate, /* createProc */ - ImgBmapGet, /* getProc */ - ImgBmapDisplay, /* displayProc */ - ImgBmapFree, /* freeProc */ - ImgBmapDelete, /* deleteProc */ - (Tk_ImageType *) NULL /* nextPtr */ -}; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL, - "", Tk_Offset(BitmapMaster, bgUid), 0}, - {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL, - "#000000", Tk_Offset(BitmapMaster, fgUid), 0}, - {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapMaster, maskDataString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(BitmapMaster, maskFileString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * The following data structure is used to describe the state of - * parsing a bitmap file or string. It is used for communication - * between TkGetBitmapData and NextBitmapWord. - */ - -#define MAX_WORD_LENGTH 100 -typedef struct ParseInfo { - char *string; /* Next character of string data for bitmap, - * or NULL if bitmap is being read from - * file. */ - Tcl_Channel chan; /* File containing bitmap data, or NULL - * if no file. */ - char word[MAX_WORD_LENGTH+1]; - /* Current word of bitmap data, NULL - * terminated. */ - int wordLength; /* Number of non-NULL bytes in word. */ -} ParseInfo; - -/* - * Prototypes for procedures used only locally in this file: - */ - -static int ImgBmapCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void ImgBmapCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void ImgBmapConfigureInstance _ANSI_ARGS_(( - BitmapInstance *instancePtr)); -static int ImgBmapConfigureMaster _ANSI_ARGS_(( - BitmapMaster *masterPtr, int argc, char **argv, - int flags)); -static int NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr)); - -/* - *---------------------------------------------------------------------- - * - * ImgBmapCreate -- - * - * This procedure is called by the Tk image code to create "test" - * images. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * The data structure for a new image is allocated. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr) - Tcl_Interp *interp; /* Interpreter for application containing - * image. */ - char *name; /* Name to use for image. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings for options (doesn't - * include image name or type). */ - Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ - Tk_ImageMaster master; /* Token for image, to be used by us in - * later callbacks. */ - ClientData *clientDataPtr; /* Store manager's token for image here; - * it will be returned in later callbacks. */ -{ - BitmapMaster *masterPtr; - - masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster)); - masterPtr->tkMaster = master; - masterPtr->interp = interp; - masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgBmapCmd, - (ClientData) masterPtr, ImgBmapCmdDeletedProc); - masterPtr->width = masterPtr->height = 0; - masterPtr->data = NULL; - masterPtr->maskData = NULL; - masterPtr->fgUid = NULL; - masterPtr->bgUid = NULL; - masterPtr->fileString = NULL; - masterPtr->dataString = NULL; - masterPtr->maskFileString = NULL; - masterPtr->maskDataString = NULL; - masterPtr->instancePtr = NULL; - if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) { - ImgBmapDelete((ClientData) masterPtr); - return TCL_ERROR; - } - *clientDataPtr = (ClientData) masterPtr; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapConfigureMaster -- - * - * This procedure is called when a bitmap image is created or - * reconfigured. It process configuration options and resets - * any instances of the image. - * - * Results: - * A standard Tcl return value. If TCL_ERROR is returned then - * an error message is left in masterPtr->interp->result. - * - * Side effects: - * Existing instances of the image will be redisplayed to match - * the new configuration options. - * - *---------------------------------------------------------------------- - */ - -static int -ImgBmapConfigureMaster(masterPtr, argc, argv, flags) - BitmapMaster *masterPtr; /* Pointer to data structure describing - * overall bitmap image to (reconfigure). */ - int argc; /* Number of entries in argv. */ - char **argv; /* Pairs of configuration options for image. */ - int flags; /* Flags to pass to Tk_ConfigureWidget, - * such as TK_CONFIG_ARGV_ONLY. */ -{ - BitmapInstance *instancePtr; - int maskWidth, maskHeight, dummy1, dummy2; - - if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp), - configSpecs, argc, argv, (char *) masterPtr, flags) - != TCL_OK) { - return TCL_ERROR; - } - - /* - * Parse the bitmap and/or mask to create binary data. Make sure that - * the bitmap and mask have the same dimensions. - */ - - if (masterPtr->data != NULL) { - ckfree(masterPtr->data); - masterPtr->data = NULL; - } - if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) { - masterPtr->data = TkGetBitmapData(masterPtr->interp, - masterPtr->dataString, masterPtr->fileString, - &masterPtr->width, &masterPtr->height, &dummy1, &dummy2); - if (masterPtr->data == NULL) { - return TCL_ERROR; - } - } - if (masterPtr->maskData != NULL) { - ckfree(masterPtr->maskData); - masterPtr->maskData = NULL; - } - if ((masterPtr->maskFileString != NULL) - || (masterPtr->maskDataString != NULL)) { - if (masterPtr->data == NULL) { - masterPtr->interp->result = "can't have mask without bitmap"; - return TCL_ERROR; - } - masterPtr->maskData = TkGetBitmapData(masterPtr->interp, - masterPtr->maskDataString, masterPtr->maskFileString, - &maskWidth, &maskHeight, &dummy1, &dummy2); - if (masterPtr->maskData == NULL) { - return TCL_ERROR; - } - if ((maskWidth != masterPtr->width) - || (maskHeight != masterPtr->height)) { - ckfree(masterPtr->maskData); - masterPtr->maskData = NULL; - masterPtr->interp->result = "bitmap and mask have different sizes"; - return TCL_ERROR; - } - } - - /* - * Cycle through all of the instances of this image, regenerating - * the information for each instance. Then force the image to be - * redisplayed everywhere that it is used. - */ - - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - ImgBmapConfigureInstance(instancePtr); - } - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width, - masterPtr->height, masterPtr->width, masterPtr->height); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapConfigureInstance -- - * - * This procedure is called to create displaying information for - * a bitmap image instance based on the configuration information - * in the master. It is invoked both when new instances are - * created and when the master is reconfigured. - * - * Results: - * None. - * - * Side effects: - * Generates errors via Tcl_BackgroundError if there are problems - * in setting up the instance. - * - *---------------------------------------------------------------------- - */ - -static void -ImgBmapConfigureInstance(instancePtr) - BitmapInstance *instancePtr; /* Instance to reconfigure. */ -{ - BitmapMaster *masterPtr = instancePtr->masterPtr; - XColor *colorPtr; - XGCValues gcValues; - GC gc; - unsigned int mask; - - /* - * For each of the options in masterPtr, translate the string - * form into an internal form appropriate for instancePtr. - */ - - if (*masterPtr->bgUid != 0) { - colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin, - masterPtr->bgUid); - if (colorPtr == NULL) { - goto error; - } - } else { - colorPtr = NULL; - } - if (instancePtr->bg != NULL) { - Tk_FreeColor(instancePtr->bg); - } - instancePtr->bg = colorPtr; - - colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin, - masterPtr->fgUid); - if (colorPtr == NULL) { - goto error; - } - if (instancePtr->fg != NULL) { - Tk_FreeColor(instancePtr->fg); - } - instancePtr->fg = colorPtr; - - if (instancePtr->bitmap != None) { - Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->bitmap); - instancePtr->bitmap = None; - } - if (masterPtr->data != NULL) { - instancePtr->bitmap = XCreateBitmapFromData( - Tk_Display(instancePtr->tkwin), - RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)), - masterPtr->data, (unsigned) masterPtr->width, - (unsigned) masterPtr->height); - } - - if (instancePtr->mask != None) { - Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask); - instancePtr->mask = None; - } - if (masterPtr->maskData != NULL) { - instancePtr->mask = XCreateBitmapFromData( - Tk_Display(instancePtr->tkwin), - RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)), - masterPtr->maskData, (unsigned) masterPtr->width, - (unsigned) masterPtr->height); - } - - if (masterPtr->data != NULL) { - gcValues.foreground = instancePtr->fg->pixel; - gcValues.graphics_exposures = False; - mask = GCForeground|GCGraphicsExposures; - if (instancePtr->bg != NULL) { - gcValues.background = instancePtr->bg->pixel; - mask |= GCBackground; - if (instancePtr->mask != None) { - gcValues.clip_mask = instancePtr->mask; - mask |= GCClipMask; - } - } else { - gcValues.clip_mask = instancePtr->bitmap; - mask |= GCClipMask; - } - gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues); - } else { - gc = None; - } - if (instancePtr->gc != None) { - Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc); - } - instancePtr->gc = gc; - return; - - error: - /* - * An error occurred: clear the graphics context in the instance to - * make it clear that this instance cannot be displayed. Then report - * the error. - */ - - if (instancePtr->gc != None) { - Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc); - } - instancePtr->gc = None; - Tcl_AddErrorInfo(masterPtr->interp, "\n (while configuring image \""); - Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); - Tcl_AddErrorInfo(masterPtr->interp, "\")"); - Tcl_BackgroundError(masterPtr->interp); -} - -/* - *---------------------------------------------------------------------- - * - * TkGetBitmapData -- - * - * Given a file name or ASCII string, this procedure parses the - * file or string contents to produce binary data for a bitmap. - * - * Results: - * If the bitmap description was parsed successfully then the - * return value is a malloc-ed array containing the bitmap data. - * The dimensions of the data are stored in *widthPtr and - * *heightPtr. *hotXPtr and *hotYPtr are set to the bitmap - * hotspot if one is defined, otherwise they are set to -1, -1. - * If an error occurred, NULL is returned and an error message is - * left in interp->result. - * - * Side effects: - * A bitmap is created. - * - *---------------------------------------------------------------------- - */ - -char * -TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr, - hotXPtr, hotYPtr) - Tcl_Interp *interp; /* For reporting errors, or NULL. */ - char *string; /* String describing bitmap. May - * be NULL. */ - char *fileName; /* Name of file containing bitmap - * description. Used only if string - * is NULL. Must not be NULL if - * string is NULL. */ - int *widthPtr, *heightPtr; /* Dimensions of bitmap get returned - * here. */ - int *hotXPtr, *hotYPtr; /* Position of hot spot or -1,-1. */ -{ - int width, height, numBytes, hotX, hotY; - char *p, *end, *expandedFileName; - ParseInfo pi; - char *data = NULL; - Tcl_DString buffer; - - pi.string = string; - if (string == NULL) { - if ((interp != NULL) && Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't get bitmap data from a file in a", - " safe interpreter", (char *) NULL); - return NULL; - } - expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer); - if (expandedFileName == NULL) { - return NULL; - } - pi.chan = Tcl_OpenFileChannel(interp, expandedFileName, "r", 0); - Tcl_DStringFree(&buffer); - if (pi.chan == NULL) { - if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't read bitmap file \"", - fileName, "\": ", Tcl_PosixError(interp), - (char *) NULL); - } - return NULL; - } - } else { - pi.chan = NULL; - } - - /* - * Parse the lines that define the dimensions of the bitmap, - * plus the first line that defines the bitmap data (it declares - * the name of a data variable but doesn't include any actual - * data). These lines look something like the following: - * - * #define foo_width 16 - * #define foo_height 16 - * #define foo_x_hot 3 - * #define foo_y_hot 3 - * static char foo_bits[] = { - * - * The x_hot and y_hot lines may or may not be present. It's - * important to check for "char" in the last line, in order to - * reject old X10-style bitmaps that used shorts. - */ - - width = 0; - height = 0; - hotX = -1; - hotY = -1; - while (1) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') - && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - width = strtol(pi.word, &end, 0); - if ((end == pi.word) || (*end != 0)) { - goto error; - } - } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_') - && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - height = strtol(pi.word, &end, 0); - if ((end == pi.word) || (*end != 0)) { - goto error; - } - } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') - && (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - hotX = strtol(pi.word, &end, 0); - if ((end == pi.word) || (*end != 0)) { - goto error; - } - } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') - && (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - hotY = strtol(pi.word, &end, 0); - if ((end == pi.word) || (*end != 0)) { - goto error; - } - } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) { - while (1) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - if ((pi.word[0] == '{') && (pi.word[1] == 0)) { - goto getData; - } - } - } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) { - if (interp != NULL) { - Tcl_AppendResult(interp, "format error in bitmap data; ", - "looks like it's an obsolete X10 bitmap file", - (char *) NULL); - } - goto errorCleanup; - } - } - - /* - * Now we've read everything but the data. Allocate an array - * and read in the data. - */ - - getData: - if ((width <= 0) || (height <= 0)) { - goto error; - } - numBytes = ((width+7)/8) * height; - data = (char *) ckalloc((unsigned) numBytes); - for (p = data; numBytes > 0; p++, numBytes--) { - if (NextBitmapWord(&pi) != TCL_OK) { - goto error; - } - *p = (char) strtol(pi.word, &end, 0); - if (end == pi.word) { - goto error; - } - } - - /* - * All done. Clean up and return. - */ - - if (pi.chan != NULL) { - Tcl_Close(NULL, pi.chan); - } - *widthPtr = width; - *heightPtr = height; - *hotXPtr = hotX; - *hotYPtr = hotY; - return data; - - error: - if (interp != NULL) { - interp->result = "format error in bitmap data"; - } - errorCleanup: - if (data != NULL) { - ckfree(data); - } - if (pi.chan != NULL) { - Tcl_Close(NULL, pi.chan); - } - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * NextBitmapWord -- - * - * This procedure retrieves the next word of information (stuff - * between commas or white space) from a bitmap description. - * - * Results: - * Returns TCL_OK if all went well. In this case the next word, - * and its length, will be availble in *parseInfoPtr. If the end - * of the bitmap description was reached then TCL_ERROR is returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -NextBitmapWord(parseInfoPtr) - ParseInfo *parseInfoPtr; /* Describes what we're reading - * and where we are in it. */ -{ - char *src, *dst; - int c; - - parseInfoPtr->wordLength = 0; - dst = parseInfoPtr->word; - if (parseInfoPtr->string != NULL) { - for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ','); - src++) { - if (*src == 0) { - return TCL_ERROR; - } - } - for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) { - *dst = *src; - dst++; - parseInfoPtr->wordLength++; - if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) { - return TCL_ERROR; - } - } - parseInfoPtr->string = src; - } else { - for (c = GetByte(parseInfoPtr->chan); isspace(UCHAR(c)) || (c == ','); - c = GetByte(parseInfoPtr->chan)) { - if (c == EOF) { - return TCL_ERROR; - } - } - for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF); - c = GetByte(parseInfoPtr->chan)) { - *dst = c; - dst++; - parseInfoPtr->wordLength++; - if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) { - return TCL_ERROR; - } - } - } - if (parseInfoPtr->wordLength == 0) { - return TCL_ERROR; - } - parseInfoPtr->word[parseInfoPtr->wordLength] = 0; - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ImgBmapCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to an image managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ImgBmapCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about the image master. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - BitmapMaster *masterPtr = (BitmapMaster *) clientData; - int c, code; - size_t length; - - if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - return TCL_ERROR; - } - return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, - (char *) masterPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, (char *) NULL, 0); - } else if (argc == 3) { - code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, argv[2], 0); - } else { - code = ImgBmapConfigureMaster(masterPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - return code; - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - return TCL_ERROR; - } -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapGet -- - * - * This procedure is called for each use of a bitmap image in a - * widget. - * - * Results: - * The return value is a token for the instance, which is passed - * back to us in calls to ImgBmapDisplay and ImgBmapFree. - * - * Side effects: - * A data structure is set up for the instance (or, an existing - * instance is re-used for the new one). - * - *---------------------------------------------------------------------- - */ - -static ClientData -ImgBmapGet(tkwin, masterData) - Tk_Window tkwin; /* Window in which the instance will be - * used. */ - ClientData masterData; /* Pointer to our master structure for the - * image. */ -{ - BitmapMaster *masterPtr = (BitmapMaster *) masterData; - BitmapInstance *instancePtr; - - /* - * See if there is already an instance for this window. If so - * then just re-use it. - */ - - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - if (instancePtr->tkwin == tkwin) { - instancePtr->refCount++; - return (ClientData) instancePtr; - } - } - - /* - * The image isn't already in use in this window. Make a new - * instance of the image. - */ - - instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance)); - instancePtr->refCount = 1; - instancePtr->masterPtr = masterPtr; - instancePtr->tkwin = tkwin; - instancePtr->fg = NULL; - instancePtr->bg = NULL; - instancePtr->bitmap = None; - instancePtr->mask = None; - instancePtr->gc = None; - instancePtr->nextPtr = masterPtr->instancePtr; - masterPtr->instancePtr = instancePtr; - ImgBmapConfigureInstance(instancePtr); - - /* - * If this is the first instance, must set the size of the image. - */ - - if (instancePtr->nextPtr == NULL) { - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width, - masterPtr->height); - } - - return (ClientData) instancePtr; -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapDisplay -- - * - * This procedure is invoked to draw a bitmap image. - * - * Results: - * None. - * - * Side effects: - * A portion of the image gets rendered in a pixmap or window. - * - *---------------------------------------------------------------------- - */ - -static void -ImgBmapDisplay(clientData, display, drawable, imageX, imageY, width, - height, drawableX, drawableY) - ClientData clientData; /* Pointer to BitmapInstance structure for - * for instance to be displayed. */ - Display *display; /* Display on which to draw image. */ - Drawable drawable; /* Pixmap or window in which to draw image. */ - int imageX, imageY; /* Upper-left corner of region within image - * to draw. */ - int width, height; /* Dimensions of region within image to draw. */ - int drawableX, drawableY; /* Coordinates within drawable that - * correspond to imageX and imageY. */ -{ - BitmapInstance *instancePtr = (BitmapInstance *) clientData; - int masking; - - /* - * If there's no graphics context, it means that an error occurred - * while creating the image instance so it can't be displayed. - */ - - if (instancePtr->gc == None) { - return; - } - - /* - * If masking is in effect, must modify the mask origin within - * the graphics context to line up with the image's origin. - * Then draw the image and reset the clip origin, if there's - * a mask. - */ - - masking = (instancePtr->mask != None) || (instancePtr->bg == NULL); - if (masking) { - XSetClipOrigin(display, instancePtr->gc, drawableX - imageX, - drawableY - imageY); - } - XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc, - imageX, imageY, (unsigned) width, (unsigned) height, - drawableX, drawableY, 1); - if (masking) { - XSetClipOrigin(display, instancePtr->gc, 0, 0); - } -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapFree -- - * - * This procedure is called when a widget ceases to use a - * particular instance of an image. - * - * Results: - * None. - * - * Side effects: - * Internal data structures get cleaned up. - * - *---------------------------------------------------------------------- - */ - -static void -ImgBmapFree(clientData, display) - ClientData clientData; /* Pointer to BitmapInstance structure for - * for instance to be displayed. */ - Display *display; /* Display containing window that used image. */ -{ - BitmapInstance *instancePtr = (BitmapInstance *) clientData; - BitmapInstance *prevPtr; - - instancePtr->refCount--; - if (instancePtr->refCount > 0) { - return; - } - - /* - * There are no more uses of the image within this widget. Free - * the instance structure. - */ - - if (instancePtr->fg != NULL) { - Tk_FreeColor(instancePtr->fg); - } - if (instancePtr->bg != NULL) { - Tk_FreeColor(instancePtr->bg); - } - if (instancePtr->bitmap != None) { - Tk_FreePixmap(display, instancePtr->bitmap); - } - if (instancePtr->mask != None) { - Tk_FreePixmap(display, instancePtr->mask); - } - if (instancePtr->gc != None) { - Tk_FreeGC(display, instancePtr->gc); - } - if (instancePtr->masterPtr->instancePtr == instancePtr) { - instancePtr->masterPtr->instancePtr = instancePtr->nextPtr; - } else { - for (prevPtr = instancePtr->masterPtr->instancePtr; - prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) { - /* Empty loop body */ - } - prevPtr->nextPtr = instancePtr->nextPtr; - } - ckfree((char *) instancePtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapDelete -- - * - * This procedure is called by the image code to delete the - * master structure for an image. - * - * Results: - * None. - * - * Side effects: - * Resources associated with the image get freed. - * - *---------------------------------------------------------------------- - */ - -static void -ImgBmapDelete(masterData) - ClientData masterData; /* Pointer to BitmapMaster structure for - * image. Must not have any more instances. */ -{ - BitmapMaster *masterPtr = (BitmapMaster *) masterData; - - if (masterPtr->instancePtr != NULL) { - panic("tried to delete bitmap image when instances still exist"); - } - masterPtr->tkMaster = NULL; - if (masterPtr->imageCmd != NULL) { - Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd); - } - if (masterPtr->data != NULL) { - ckfree(masterPtr->data); - } - if (masterPtr->maskData != NULL) { - ckfree(masterPtr->maskData); - } - Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0); - ckfree((char *) masterPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImgBmapCmdDeletedProc -- - * - * This procedure is invoked when the image command for an image - * is deleted. It deletes the image. - * - * Results: - * None. - * - * Side effects: - * The image is deleted. - * - *---------------------------------------------------------------------- - */ - -static void -ImgBmapCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to BitmapMaster structure for - * image. */ -{ - BitmapMaster *masterPtr = (BitmapMaster *) clientData; - - masterPtr->imageCmd = NULL; - if (masterPtr->tkMaster != NULL) { - Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); - } -} - -/* - *---------------------------------------------------------------------- - * - * GetByte -- - * - * Get the next byte from the open channel. - * - * Results: - * The next byte or EOF. - * - * Side effects: - * We read from the channel. - * - *---------------------------------------------------------------------- - */ - -static int -GetByte(chan) - Tcl_Channel chan; /* The channel we read from. */ -{ - char buffer; - int size; - - size = Tcl_Read(chan, &buffer, 1); - if (size <= 0) { - return EOF; - } else { - return buffer; - } -} diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c deleted file mode 100644 index d9dd900..0000000 --- a/generic/tkImgGIF.c +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * tkImgGIF.c -- - * - * A photo image file handler for GIF files. Reads 87a and 89a GIF - * files. At present there is no write function. GIF images may be - * read using the -data option of the photo image by representing - * the data as BASE64 encoded ascii. Derived from the giftoppm code - * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2 - * distribution. - * - * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee - * Copyright (c) 1995-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * This file also contains code from the giftoppm program, which is - * copyrighted as follows: - * - * +-------------------------------------------------------------------+ - * | Copyright 1990, David Koblas. | - * | Permission to use, copy, modify, and distribute this software | - * | and its documentation for any purpose and without fee is hereby | - * | granted, provided that the above copyright notice appear in all | - * | copies and that both that copyright notice and this permission | - * | notice appear in supporting documentation. This software is | - * | provided "as is" without express or implied warranty. | - * +-------------------------------------------------------------------+ - * - * RCS: @(#) $Id: tkImgGIF.c,v 1.2 1998/09/14 18:23:12 stanton Exp $ - */ - -/* - * GIF's are represented as data in base64 format. - * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes. - * A-Z, a-z, 0-9, + and / represent the 64 values (in order). - * '=' is a trailing padding char when the un-encoded data is not a - * multiple of 3 bytes. We'll ignore white space when encountered. - * Any other invalid character is treated as an EOF - */ - -#define GIF_SPECIAL (256) -#define GIF_PAD (GIF_SPECIAL+1) -#define GIF_SPACE (GIF_SPECIAL+2) -#define GIF_BAD (GIF_SPECIAL+3) -#define GIF_DONE (GIF_SPECIAL+4) - -/* - * structure to "mimic" FILE for Mread, so we can look like fread. - * The decoder state keeps track of which byte we are about to read, - * or EOF. - */ - -typedef struct mFile { - unsigned char *data; /* mmencoded source string */ - int c; /* bits left over from previous character */ - int state; /* decoder state (0-4 or GIF_DONE) */ -} MFile; - -#include "tkInt.h" -#include "tkPort.h" - -/* - * The format record for the GIF file format: - */ - -static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName, - char *formatString, int *widthPtr, int *heightPtr)); -static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, char *formatString, - Tk_PhotoHandle imageHandle, int destX, int destY, - int width, int height, int srcX, int srcY)); -static int StringMatchGIF _ANSI_ARGS_(( char *string, - char *formatString, int *widthPtr, int *heightPtr)); -static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, char *string, - char *formatString, Tk_PhotoHandle imageHandle, - int destX, int destY, int width, int height, - int srcX, int srcY)); - -Tk_PhotoImageFormat tkImgFmtGIF = { - "GIF", /* name */ - FileMatchGIF, /* fileMatchProc */ - StringMatchGIF, /* stringMatchProc */ - FileReadGIF, /* fileReadProc */ - StringReadGIF, /* stringReadProc */ - NULL, /* fileWriteProc */ - NULL, /* stringWriteProc */ -}; - -#define INTERLACE 0x40 -#define LOCALCOLORMAP 0x80 -#define BitSet(byte, bit) (((byte) & (bit)) == (bit)) -#define MAXCOLORMAPSIZE 256 -#define CM_RED 0 -#define CM_GREEN 1 -#define CM_BLUE 2 -#define CM_ALPHA 3 -#define MAX_LWZ_BITS 12 -#define LM_to_uint(a,b) (((b)<<8)|(a)) -#define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0) - -/* - * HACK ALERT!! HACK ALERT!! HACK ALERT!! - * This code is hard-wired for reading from files. In order to read - * from a data stream, we'll trick fread so we can reuse the same code - */ - -static int fromData=0; - -/* - * Prototypes for local procedures defined in this file: - */ - -static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label, - int *transparent)); -static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size, - int flag)); -static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan, - unsigned char *buf)); -static int LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag, - int input_code_size)); -static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number, - unsigned char buffer[MAXCOLORMAPSIZE][4])); -static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan, - int *widthPtr, int *heightPtr)); -static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp, - char *imagePtr, Tcl_Channel chan, - int len, int rows, - unsigned char cmap[MAXCOLORMAPSIZE][4], - int width, int height, int srcX, int srcY, - int interlace, int transparent)); - -/* - * these are for the BASE64 image reader code only - */ - -static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size, - size_t count, Tcl_Channel chan)); -static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size, - size_t count, MFile *handle)); -static int Mgetc _ANSI_ARGS_((MFile *handle)); -static int char64 _ANSI_ARGS_((int c)); -static void mInit _ANSI_ARGS_((unsigned char *string, - MFile *handle)); - -/* - *---------------------------------------------------------------------- - * - * FileMatchGIF -- - * - * This procedure is invoked by the photo image type to see if - * a file contains image data in GIF format. - * - * Results: - * The return value is 1 if the first characters in file f look - * like GIF data, and 0 otherwise. - * - * Side effects: - * The access position in f may change. - * - *---------------------------------------------------------------------- - */ - -static int -FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr) - Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here if the file is a valid - * raw GIF file. */ -{ - return ReadGIFHeader(chan, widthPtr, heightPtr); -} - -/* - *---------------------------------------------------------------------- - * - * FileReadGIF -- - * - * This procedure is called by the photo image type to read - * GIF format data from a file and write it into a given - * photo image. - * - * Results: - * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. - * - * Side effects: - * The access position in file f is changed, and new data is - * added to the image given by imageHandle. - * - *---------------------------------------------------------------------- - */ - -static int -FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, - width, height, srcX, srcY) - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ - Tk_PhotoHandle imageHandle; /* The photo image to write into. */ - int destX, destY; /* Coordinates of top-left pixel in - * photo image to be written to. */ - int width, height; /* Dimensions of block of photo image to - * be written to. */ - int srcX, srcY; /* Coordinates of top-left pixel to be used - * in image being read. */ -{ - int fileWidth, fileHeight; - int nBytes; - Tk_PhotoImageBlock block; - unsigned char buf[100]; - int bitPixel; - unsigned char colorMap[MAXCOLORMAPSIZE][4]; - int transparent = -1; - - if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) { - Tcl_AppendResult(interp, "couldn't read GIF header from file \"", - fileName, "\"", NULL); - return TCL_ERROR; - } - if ((fileWidth <= 0) || (fileHeight <= 0)) { - Tcl_AppendResult(interp, "GIF image file \"", fileName, - "\" has dimension(s) <= 0", (char *) NULL); - return TCL_ERROR; - } - - if (Fread(buf, 1, 3, chan) != 3) { - return TCL_OK; - } - bitPixel = 2<<(buf[0]&0x07); - - if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */ - if (!ReadColorMap(chan, bitPixel, colorMap)) { - Tcl_AppendResult(interp, "error reading color map", - (char *) NULL); - return TCL_ERROR; - } - } - - if ((srcX + width) > fileWidth) { - width = fileWidth - srcX; - } - if ((srcY + height) > fileHeight) { - height = fileHeight - srcY; - } - if ((width <= 0) || (height <= 0) - || (srcX >= fileWidth) || (srcY >= fileHeight)) { - return TCL_OK; - } - - Tk_PhotoExpand(imageHandle, destX + width, destY + height); - - block.width = width; - block.height = height; - block.pixelSize = 4; - block.pitch = block.pixelSize * block.width; - block.offset[0] = 0; - block.offset[1] = 1; - block.offset[2] = 2; - nBytes = height * block.pitch; - block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); - - while (1) { - if (Fread(buf, 1, 1, chan) != 1) { - /* - * Premature end of image. We should really notify - * the user, but for now just show garbage. - */ - - break; - } - - if (buf[0] == ';') { - /* - * GIF terminator. - */ - - break; - } - - if (buf[0] == '!') { - /* - * This is a GIF extension. - */ - - if (Fread(buf, 1, 1, chan) != 1) { - interp->result = - "error reading extension function code in GIF image"; - goto error; - } - if (DoExtension(chan, buf[0], &transparent) < 0) { - interp->result = "error reading extension in GIF image"; - goto error; - } - continue; - } - - if (buf[0] != ',') { - /* - * Not a valid start character; ignore it. - */ - continue; - } - - if (Fread(buf, 1, 9, chan) != 9) { - interp->result = "couldn't read left/top/width/height in GIF image"; - goto error; - } - - bitPixel = 1<<((buf[8]&0x07)+1); - - if (BitSet(buf[8], LOCALCOLORMAP)) { - if (!ReadColorMap(chan, bitPixel, colorMap)) { - Tcl_AppendResult(interp, "error reading color map", - (char *) NULL); - goto error; - } - } - if (ReadImage(interp, (char *) block.pixelPtr, chan, width, - height, colorMap, fileWidth, fileHeight, srcX, srcY, - BitSet(buf[8], INTERLACE), transparent) != TCL_OK) { - goto error; - } - break; - } - - if (transparent == -1) { - Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height); - } else { - int x, y, end; - unsigned char *imagePtr, *rowPtr, *pixelPtr; - - imagePtr = rowPtr = block.pixelPtr; - for (y = 0; y < height; y++) { - x = 0; - pixelPtr = rowPtr; - while(x < width) { - /* search for first non-transparent pixel */ - while ((x < width) && !(pixelPtr[CM_ALPHA])) { - x++; pixelPtr += 4; - } - end = x; - /* search for first transparent pixel */ - while ((end < width) && pixelPtr[CM_ALPHA]) { - end++; pixelPtr += 4; - } - if (end > x) { - block.pixelPtr = rowPtr + 4 * x; - Tk_PhotoPutBlock(imageHandle, &block, destX+x, - destY+y, end-x, 1); - } - x = end; - } - rowPtr += block.pitch; - } - block.pixelPtr = imagePtr; - } - ckfree((char *) block.pixelPtr); - return TCL_OK; - - error: - ckfree((char *) block.pixelPtr); - return TCL_ERROR; - -} - -/* - *---------------------------------------------------------------------- - * - * StringMatchGIF -- - * - * This procedure is invoked by the photo image type to see if - * a string contains image data in GIF format. - * - * Results: - * The return value is 1 if the first characters in the string - * like GIF data, and 0 otherwise. - * - * Side effects: - * the size of the image is placed in widthPre and heightPtr. - * - *---------------------------------------------------------------------- - */ - -static int -StringMatchGIF(string, formatString, widthPtr, heightPtr) - char *string; /* the string containing the image data */ - char *formatString; /* the image format string */ - int *widthPtr; /* where to put the string width */ - int *heightPtr; /* where to put the string height */ -{ - unsigned char header[10]; - int got; - MFile handle; - mInit((unsigned char *) string, &handle); - got = Mread(header, 10, 1, &handle); - if (got != 10 - || ((strncmp("GIF87a", (char *) header, 6) != 0) - && (strncmp("GIF89a", (char *) header, 6) != 0))) { - return 0; - } - *widthPtr = LM_to_uint(header[6],header[7]); - *heightPtr = LM_to_uint(header[8],header[9]); - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * StringReadGif -- -- - * - * This procedure is called by the photo image type to read - * GIF format data from a base64 encoded string, and give it to - * the photo image. - * - * Results: - * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. - * - * Side effects: - * new data is added to the image given by imageHandle. This - * procedure calls FileReadGif by redefining the operation of - * fprintf temporarily. - * - *---------------------------------------------------------------------- - */ - -static int -StringReadGIF(interp,string,formatString,imageHandle, - destX, destY, width, height, srcX, srcY) - Tcl_Interp *interp; /* interpreter for reporting errors in */ - char *string; /* string containing the image */ - char *formatString; /* format string if any */ - Tk_PhotoHandle imageHandle; /* the image to write this data into */ - int destX, destY; /* The rectangular region of the */ - int width, height; /* image to copy */ - int srcX, srcY; -{ - int result; - MFile handle; - mInit((unsigned char *)string,&handle); - fromData = 1; - result = FileReadGIF(interp, (Tcl_Channel) &handle, "inline data", - formatString, imageHandle, destX, destY, width, height, - srcX, srcY); - fromData = 0; - return(result); -} - -/* - *---------------------------------------------------------------------- - * - * ReadGIFHeader -- - * - * This procedure reads the GIF header from the beginning of a - * GIF file and returns the dimensions of the image. - * - * Results: - * The return value is 1 if file "f" appears to start with - * a valid GIF header, 0 otherwise. If the header is valid, - * then *widthPtr and *heightPtr are modified to hold the - * dimensions of the image. - * - * Side effects: - * The access position in f advances. - * - *---------------------------------------------------------------------- - */ - -static int -ReadGIFHeader(chan, widthPtr, heightPtr) - Tcl_Channel chan; /* Image file to read the header from */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here. */ -{ - unsigned char buf[7]; - - if ((Fread(buf, 1, 6, chan) != 6) - || ((strncmp("GIF87a", (char *) buf, 6) != 0) - && (strncmp("GIF89a", (char *) buf, 6) != 0))) { - return 0; - } - - if (Fread(buf, 1, 4, chan) != 4) { - return 0; - } - - *widthPtr = LM_to_uint(buf[0],buf[1]); - *heightPtr = LM_to_uint(buf[2],buf[3]); - return 1; -} - -/* - *----------------------------------------------------------------- - * The code below is copied from the giftoppm program and modified - * just slightly. - *----------------------------------------------------------------- - */ - -static int -ReadColorMap(chan, number, buffer) - Tcl_Channel chan; - int number; - unsigned char buffer[MAXCOLORMAPSIZE][4]; -{ - int i; - unsigned char rgb[3]; - - for (i = 0; i < number; ++i) { - if (! ReadOK(chan, rgb, sizeof(rgb))) { - return 0; - } - - buffer[i][CM_RED] = rgb[0] ; - buffer[i][CM_GREEN] = rgb[1] ; - buffer[i][CM_BLUE] = rgb[2] ; - buffer[i][CM_ALPHA] = 255 ; - } - return 1; -} - - - -static int -DoExtension(chan, label, transparent) - Tcl_Channel chan; - int label; - int *transparent; -{ - static unsigned char buf[256]; - int count; - - switch (label) { - case 0x01: /* Plain Text Extension */ - break; - - case 0xff: /* Application Extension */ - break; - - case 0xfe: /* Comment Extension */ - do { - count = GetDataBlock(chan, (unsigned char*) buf); - } while (count > 0); - return count; - - case 0xf9: /* Graphic Control Extension */ - count = GetDataBlock(chan, (unsigned char*) buf); - if (count < 0) { - return 1; - } - if ((buf[0] & 0x1) != 0) { - *transparent = buf[3]; - } - - do { - count = GetDataBlock(chan, (unsigned char*) buf); - } while (count > 0); - return count; - } - - do { - count = GetDataBlock(chan, (unsigned char*) buf); - } while (count > 0); - return count; -} - -static int ZeroDataBlock = 0; - -static int -GetDataBlock(chan, buf) - Tcl_Channel chan; - unsigned char *buf; -{ - unsigned char count; - - if (! ReadOK(chan, &count,1)) { - return -1; - } - - ZeroDataBlock = count == 0; - - if ((count != 0) && (! ReadOK(chan, buf, count))) { - return -1; - } - - return count; -} - - -static int -ReadImage(interp, imagePtr, chan, len, rows, cmap, - width, height, srcX, srcY, interlace, transparent) - Tcl_Interp *interp; - char *imagePtr; - Tcl_Channel chan; - int len, rows; - unsigned char cmap[MAXCOLORMAPSIZE][4]; - int width, height; - int srcX, srcY; - int interlace; - int transparent; -{ - unsigned char c; - int v; - int xpos = 0, ypos = 0, pass = 0; - char *pixelPtr; - - - /* - * Initialize the Compression routines - */ - if (! ReadOK(chan, &c, 1)) { - Tcl_AppendResult(interp, "error reading GIF image: ", - Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; - } - - if (LWZReadByte(chan, 1, c) < 0) { - interp->result = "format error in GIF image"; - return TCL_ERROR; - } - - if (transparent!=-1) { - cmap[transparent][CM_RED] = 0; - cmap[transparent][CM_GREEN] = 0; - cmap[transparent][CM_BLUE] = 0; - cmap[transparent][CM_ALPHA] = 0; - } - - pixelPtr = imagePtr; - while ((v = LWZReadByte(chan, 0, c)) >= 0 ) { - - if ((xpos>=srcX) && (xpos<srcX+len) && - (ypos>=srcY) && (ypos<srcY+rows)) { - *pixelPtr++ = cmap[v][CM_RED]; - *pixelPtr++ = cmap[v][CM_GREEN]; - *pixelPtr++ = cmap[v][CM_BLUE]; - *pixelPtr++ = cmap[v][CM_ALPHA]; - } - - ++xpos; - if (xpos == width) { - xpos = 0; - if (interlace) { - switch (pass) { - case 0: - case 1: - ypos += 8; break; - case 2: - ypos += 4; break; - case 3: - ypos += 2; break; - } - - while (ypos >= height) { - ++pass; - switch (pass) { - case 1: - ypos = 4; break; - case 2: - ypos = 2; break; - case 3: - ypos = 1; break; - default: - return TCL_OK; - } - } - } else { - ++ypos; - } - pixelPtr = imagePtr + (ypos-srcY) * len * 4; - } - if (ypos >= height) - break; - } - return TCL_OK; -} - -static int -LWZReadByte(chan, flag, input_code_size) - Tcl_Channel chan; - int flag; - int input_code_size; -{ - static int fresh = 0; - int code, incode; - static int code_size, set_code_size; - static int max_code, max_code_size; - static int firstcode, oldcode; - static int clear_code, end_code; - static int table[2][(1<< MAX_LWZ_BITS)]; - static int stack[(1<<(MAX_LWZ_BITS))*2], *sp; - register int i; - - if (flag) { - set_code_size = input_code_size; - code_size = set_code_size+1; - clear_code = 1 << set_code_size ; - end_code = clear_code + 1; - max_code_size = 2*clear_code; - max_code = clear_code+2; - - GetCode(chan, 0, 1); - - fresh = 1; - - for (i = 0; i < clear_code; ++i) { - table[0][i] = 0; - table[1][i] = i; - } - for (; i < (1<<MAX_LWZ_BITS); ++i) { - table[0][i] = table[1][0] = 0; - } - - sp = stack; - - return 0; - } else if (fresh) { - fresh = 0; - do { - firstcode = oldcode = GetCode(chan, code_size, 0); - } while (firstcode == clear_code); - return firstcode; - } - - if (sp > stack) { - return *--sp; - } - - while ((code = GetCode(chan, code_size, 0)) >= 0) { - if (code == clear_code) { - for (i = 0; i < clear_code; ++i) { - table[0][i] = 0; - table[1][i] = i; - } - - for (; i < (1<<MAX_LWZ_BITS); ++i) { - table[0][i] = table[1][i] = 0; - } - - code_size = set_code_size+1; - max_code_size = 2*clear_code; - max_code = clear_code+2; - sp = stack; - firstcode = oldcode = GetCode(chan, code_size, 0); - return firstcode; - - } else if (code == end_code) { - int count; - unsigned char buf[260]; - - if (ZeroDataBlock) { - return -2; - } - - while ((count = GetDataBlock(chan, buf)) > 0) - /* Empty body */; - - if (count != 0) { - return -2; - } - } - - incode = code; - - if (code >= max_code) { - *sp++ = firstcode; - code = oldcode; - } - - while (code >= clear_code) { - *sp++ = table[1][code]; - if (code == table[0][code]) { - return -2; - - /* - * Used to be this instead, Steve Ball suggested - * the change to just return. - printf("circular table entry BIG ERROR\n"); - */ - } - code = table[0][code]; - } - - *sp++ = firstcode = table[1][code]; - - if ((code = max_code) <(1<<MAX_LWZ_BITS)) { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++max_code; - if ((max_code>=max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) { - max_code_size *= 2; - ++code_size; - } - } - - oldcode = incode; - - if (sp > stack) - return *--sp; - } - return code; -} - - -static int -GetCode(chan, code_size, flag) - Tcl_Channel chan; - int code_size; - int flag; -{ - static unsigned char buf[280]; - static int curbit, lastbit, done, last_byte; - int i, j, ret; - unsigned char count; - - if (flag) { - curbit = 0; - lastbit = 0; - done = 0; - return 0; - } - - - if ( (curbit+code_size) >= lastbit) { - if (done) { - /* ran off the end of my bits */ - return -1; - } - if (last_byte >= 2) { - buf[0] = buf[last_byte-2]; - } - if (last_byte >= 1) { - buf[1] = buf[last_byte-1]; - } - - if ((count = GetDataBlock(chan, &buf[2])) == 0) { - done = 1; - } - - last_byte = 2 + count; - curbit = (curbit - lastbit) + 16; - lastbit = (2+count)*8 ; - } - - ret = 0; - for (i = curbit, j = 0; j < code_size; ++i, ++j) { - ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; - } - - curbit += code_size; - - return ret; -} - -/* - *---------------------------------------------------------------------- - * - * Minit -- -- - * - * This procedure initializes a base64 decoder handle - * - * Results: - * none - * - * Side effects: - * the base64 handle is initialized - * - *---------------------------------------------------------------------- - */ - -static void -mInit(string, handle) - unsigned char *string; /* string containing initial mmencoded data */ - MFile *handle; /* mmdecode "file" handle */ -{ - handle->data = string; - handle->state = 0; -} - -/* - *---------------------------------------------------------------------- - * - * Mread -- - * - * This procedure is invoked by the GIF file reader as a - * temporary replacement for "fread", to get GIF data out - * of a string (using Mgetc). - * - * Results: - * The return value is the number of characters "read" - * - * Side effects: - * The base64 handle will change state. - * - *---------------------------------------------------------------------- - */ - -static int -Mread(dst, chunkSize, numChunks, handle) - unsigned char *dst; /* where to put the result */ - size_t chunkSize; /* size of each transfer */ - size_t numChunks; /* number of chunks */ - MFile *handle; /* mmdecode "file" handle */ -{ - register int i, c; - int count = chunkSize * numChunks; - - for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) { - *dst++ = c; - } - return i; -} - -/* - * get the next decoded character from an mmencode handle - * This causes at least 1 character to be "read" from the encoded string - */ - -/* - *---------------------------------------------------------------------- - * - * Mgetc -- - * - * This procedure decodes and returns the next byte from a base64 - * encoded string. - * - * Results: - * The next byte (or GIF_DONE) is returned. - * - * Side effects: - * The base64 handle will change state. - * - *---------------------------------------------------------------------- - */ - -static int -Mgetc(handle) - MFile *handle; /* Handle containing decoder data and state. */ -{ - int c; - int result = 0; /* Initialization needed only to prevent - * gcc compiler warning. */ - - if (handle->state == GIF_DONE) { - return(GIF_DONE); - } - - do { - c = char64(*handle->data); - handle->data++; - } while (c==GIF_SPACE); - - if (c>GIF_SPECIAL) { - handle->state = GIF_DONE; - return(handle->state ? handle->c : GIF_DONE); - } - - switch (handle->state++) { - case 0: - handle->c = c<<2; - result = Mgetc(handle); - break; - case 1: - result = handle->c | (c>>4); - handle->c = (c&0xF)<<4; - break; - case 2: - result = handle->c | (c>>2); - handle->c = (c&0x3) << 6; - break; - case 3: - result = handle->c | c; - handle->state = 0; - break; - } - return(result); -} - -/* - *---------------------------------------------------------------------- - * - * char64 -- - * - * This procedure converts a base64 ascii character into its binary - * equivalent. This code is a slightly modified version of the - * char64 proc in N. Borenstein's metamail decoder. - * - * Results: - * The binary value, or an error code. - * - * Side effects: - * None. - *---------------------------------------------------------------------- - */ - -static int -char64(c) -int c; -{ - switch(c) { - case 'A': return(0); case 'B': return(1); case 'C': return(2); - case 'D': return(3); case 'E': return(4); case 'F': return(5); - case 'G': return(6); case 'H': return(7); case 'I': return(8); - case 'J': return(9); case 'K': return(10); case 'L': return(11); - case 'M': return(12); case 'N': return(13); case 'O': return(14); - case 'P': return(15); case 'Q': return(16); case 'R': return(17); - case 'S': return(18); case 'T': return(19); case 'U': return(20); - case 'V': return(21); case 'W': return(22); case 'X': return(23); - case 'Y': return(24); case 'Z': return(25); case 'a': return(26); - case 'b': return(27); case 'c': return(28); case 'd': return(29); - case 'e': return(30); case 'f': return(31); case 'g': return(32); - case 'h': return(33); case 'i': return(34); case 'j': return(35); - case 'k': return(36); case 'l': return(37); case 'm': return(38); - case 'n': return(39); case 'o': return(40); case 'p': return(41); - case 'q': return(42); case 'r': return(43); case 's': return(44); - case 't': return(45); case 'u': return(46); case 'v': return(47); - case 'w': return(48); case 'x': return(49); case 'y': return(50); - case 'z': return(51); case '0': return(52); case '1': return(53); - case '2': return(54); case '3': return(55); case '4': return(56); - case '5': return(57); case '6': return(58); case '7': return(59); - case '8': return(60); case '9': return(61); case '+': return(62); - case '/': return(63); - - case ' ': case '\t': case '\n': case '\r': case '\f': return(GIF_SPACE); - case '=': return(GIF_PAD); - case '\0': return(GIF_DONE); - default: return(GIF_BAD); - } -} - -/* - *---------------------------------------------------------------------- - * - * Fread -- - * - * This procedure calls either fread or Mread to read data - * from a file or a base64 encoded string. - * - * Results: - same as fread - * - *---------------------------------------------------------------------- - */ - -static int -Fread(dst, hunk, count, chan) - unsigned char *dst; /* where to put the result */ - size_t hunk,count; /* how many */ - Tcl_Channel chan; -{ - if (fromData) { - return(Mread(dst, hunk, count, (MFile *) chan)); - } else { - return Tcl_Read(chan, (char *) dst, (int) (hunk * count)); - } -} diff --git a/generic/tkImgPPM.c b/generic/tkImgPPM.c deleted file mode 100644 index 7573955..0000000 --- a/generic/tkImgPPM.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * tkImgPPM.c -- - * - * A photo image file handler for PPM (Portable PixMap) files. - * - * Copyright (c) 1994 The Australian National University. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * Author: Paul Mackerras (paulus@cs.anu.edu.au), - * Department of Computer Science, - * Australian National University. - * - * RCS: @(#) $Id: tkImgPPM.c,v 1.2 1998/09/14 18:23:13 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - * The maximum amount of memory to allocate for data read from the - * file. If we need more than this, we do it in pieces. - */ - -#define MAX_MEMORY 10000 /* don't allocate > 10KB */ - -/* - * Define PGM and PPM, i.e. gray images and color images. - */ - -#define PGM 1 -#define PPM 2 - -/* - * The format record for the PPM file format: - */ - -static int FileMatchPPM _ANSI_ARGS_((Tcl_Channel chan, - char *fileName, char *formatString, - int *widthPtr, int *heightPtr)); -static int FileReadPPM _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, - char *formatString, Tk_PhotoHandle imageHandle, - int destX, int destY, int width, int height, - int srcX, int srcY)); -static int FileWritePPM _ANSI_ARGS_((Tcl_Interp *interp, - char *fileName, char *formatString, - Tk_PhotoImageBlock *blockPtr)); - -Tk_PhotoImageFormat tkImgFmtPPM = { - "PPM", /* name */ - FileMatchPPM, /* fileMatchProc */ - NULL, /* stringMatchProc */ - FileReadPPM, /* fileReadProc */ - NULL, /* stringReadProc */ - FileWritePPM, /* fileWriteProc */ - NULL, /* stringWriteProc */ -}; - -/* - * Prototypes for local procedures defined in this file: - */ - -static int ReadPPMFileHeader _ANSI_ARGS_((Tcl_Channel chan, - int *widthPtr, int *heightPtr, - int *maxIntensityPtr)); - -/* - *---------------------------------------------------------------------- - * - * FileMatchPPM -- - * - * This procedure is invoked by the photo image type to see if - * a file contains image data in PPM format. - * - * Results: - * The return value is >0 if the first characters in file "f" look - * like PPM data, and 0 otherwise. - * - * Side effects: - * The access position in f may change. - * - *---------------------------------------------------------------------- - */ - -static int -FileMatchPPM(chan, fileName, formatString, widthPtr, heightPtr) - Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here if the file is a valid - * raw PPM file. */ -{ - int dummy; - - return ReadPPMFileHeader(chan, widthPtr, heightPtr, &dummy); -} - -/* - *---------------------------------------------------------------------- - * - * FileReadPPM -- - * - * This procedure is called by the photo image type to read - * PPM format data from a file and write it into a given - * photo image. - * - * Results: - * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. - * - * Side effects: - * The access position in file f is changed, and new data is - * added to the image given by imageHandle. - * - *---------------------------------------------------------------------- - */ - -static int -FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY, - width, height, srcX, srcY) - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ - Tk_PhotoHandle imageHandle; /* The photo image to write into. */ - int destX, destY; /* Coordinates of top-left pixel in - * photo image to be written to. */ - int width, height; /* Dimensions of block of photo image to - * be written to. */ - int srcX, srcY; /* Coordinates of top-left pixel to be used - * in image being read. */ -{ - int fileWidth, fileHeight, maxIntensity; - int nLines, nBytes, h, type, count; - unsigned char *pixelPtr; - Tk_PhotoImageBlock block; - - type = ReadPPMFileHeader(chan, &fileWidth, &fileHeight, &maxIntensity); - if (type == 0) { - Tcl_AppendResult(interp, "couldn't read raw PPM header from file \"", - fileName, "\"", NULL); - return TCL_ERROR; - } - if ((fileWidth <= 0) || (fileHeight <= 0)) { - Tcl_AppendResult(interp, "PPM image file \"", fileName, - "\" has dimension(s) <= 0", (char *) NULL); - return TCL_ERROR; - } - if ((maxIntensity <= 0) || (maxIntensity >= 256)) { - char buffer[30]; - - sprintf(buffer, "%d", maxIntensity); - Tcl_AppendResult(interp, "PPM image file \"", fileName, - "\" has bad maximum intensity value ", buffer, - (char *) NULL); - return TCL_ERROR; - } - - if ((srcX + width) > fileWidth) { - width = fileWidth - srcX; - } - if ((srcY + height) > fileHeight) { - height = fileHeight - srcY; - } - if ((width <= 0) || (height <= 0) - || (srcX >= fileWidth) || (srcY >= fileHeight)) { - return TCL_OK; - } - - if (type == PGM) { - block.pixelSize = 1; - block.offset[0] = 0; - block.offset[1] = 0; - block.offset[2] = 0; - } - else { - block.pixelSize = 3; - block.offset[0] = 0; - block.offset[1] = 1; - block.offset[2] = 2; - } - block.width = width; - block.pitch = block.pixelSize * fileWidth; - - Tk_PhotoExpand(imageHandle, destX + width, destY + height); - - if (srcY > 0) { - Tcl_Seek(chan, (srcY * block.pitch), SEEK_CUR); - } - - nLines = (MAX_MEMORY + block.pitch - 1) / block.pitch; - if (nLines > height) { - nLines = height; - } - if (nLines <= 0) { - nLines = 1; - } - nBytes = nLines * block.pitch; - pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); - block.pixelPtr = pixelPtr + srcX * block.pixelSize; - - for (h = height; h > 0; h -= nLines) { - if (nLines > h) { - nLines = h; - nBytes = nLines * block.pitch; - } - count = Tcl_Read(chan, (char *) pixelPtr, nBytes); - if (count != nBytes) { - Tcl_AppendResult(interp, "error reading PPM image file \"", - fileName, "\": ", - Tcl_Eof(chan) ? "not enough data" : Tcl_PosixError(interp), - (char *) NULL); - ckfree((char *) pixelPtr); - return TCL_ERROR; - } - if (maxIntensity != 255) { - unsigned char *p; - - for (p = pixelPtr; count > 0; count--, p++) { - *p = (((int) *p) * 255)/maxIntensity; - } - } - block.height = nLines; - Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines); - destY += nLines; - } - - ckfree((char *) pixelPtr); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * FileWritePPM -- - * - * This procedure is invoked to write image data to a file in PPM - * format. - * - * Results: - * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. - * - * Side effects: - * Data is written to the file given by "fileName". - * - *---------------------------------------------------------------------- - */ - -static int -FileWritePPM(interp, fileName, formatString, blockPtr) - Tcl_Interp *interp; - char *fileName; - char *formatString; - Tk_PhotoImageBlock *blockPtr; -{ - Tcl_Channel chan; - int w, h; - int greenOffset, blueOffset, nBytes; - unsigned char *pixelPtr, *pixLinePtr; - char header[30]; - - chan = Tcl_OpenFileChannel(interp, fileName, "w", 0666); - if (chan == NULL) { - return TCL_ERROR; - } - - sprintf(header, "P6\n%d %d\n255\n", blockPtr->width, blockPtr->height); - Tcl_Write(chan, header, -1); - - pixLinePtr = blockPtr->pixelPtr + blockPtr->offset[0]; - greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; - blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - - if ((greenOffset == 1) && (blueOffset == 2) && (blockPtr->pixelSize == 3) - && (blockPtr->pitch == (blockPtr->width * 3))) { - nBytes = blockPtr->height * blockPtr->pitch; - if (Tcl_Write(chan, (char *) pixLinePtr, nBytes) != nBytes) { - goto writeerror; - } - } else { - for (h = blockPtr->height; h > 0; h--) { - pixelPtr = pixLinePtr; - for (w = blockPtr->width; w > 0; w--) { - if ((Tcl_Write(chan, (char *) &pixelPtr[0], 1) == -1) - || (Tcl_Write(chan, (char *) &pixelPtr[greenOffset], 1) == -1) - || (Tcl_Write(chan, (char *) &pixelPtr[blueOffset], 1) == -1)) { - goto writeerror; - } - pixelPtr += blockPtr->pixelSize; - } - pixLinePtr += blockPtr->pitch; - } - } - - if (Tcl_Close(NULL, chan) == 0) { - return TCL_OK; - } - chan = NULL; - - writeerror: - Tcl_AppendResult(interp, "error writing \"", fileName, "\": ", - Tcl_PosixError(interp), (char *) NULL); - if (chan != NULL) { - Tcl_Close(NULL, chan); - } - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * ReadPPMFileHeader -- - * - * This procedure reads the PPM header from the beginning of a - * PPM file and returns information from the header. - * - * Results: - * The return value is PGM if file "f" appears to start with - * a valid PGM header, PPM if "f" appears to start with a valid - * PPM header, and 0 otherwise. If the header is valid, - * then *widthPtr and *heightPtr are modified to hold the - * dimensions of the image and *maxIntensityPtr is modified to - * hold the value of a "fully on" intensity value. - * - * Side effects: - * The access position in f advances. - * - *---------------------------------------------------------------------- - */ - -static int -ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) - Tcl_Channel chan; /* Image file to read the header from */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here. */ - int *maxIntensityPtr; /* The maximum intensity value for - * the image is stored here. */ -{ -#define BUFFER_SIZE 1000 - char buffer[BUFFER_SIZE]; - int i, numFields, firstInLine; - int type = 0; - char c; - - /* - * Read 4 space-separated fields from the file, ignoring - * comments (any line that starts with "#"). - */ - - if (Tcl_Read(chan, &c, 1) != 1) { - return 0; - } - firstInLine = 1; - i = 0; - for (numFields = 0; numFields < 4; numFields++) { - /* - * Skip comments and white space. - */ - - while (1) { - while (isspace(UCHAR(c))) { - firstInLine = (c == '\n'); - if (Tcl_Read(chan, &c, 1) != 1) { - return 0; - } - } - if (c != '#') { - break; - } - do { - if (Tcl_Read(chan, &c, 1) != 1) { - return 0; - } - } while (c != '\n'); - firstInLine = 1; - } - - /* - * Read a field (everything up to the next white space). - */ - - while (!isspace(UCHAR(c))) { - if (i < (BUFFER_SIZE-2)) { - buffer[i] = c; - i++; - } - if (Tcl_Read(chan, &c, 1) != 1) { - goto done; - } - } - if (i < (BUFFER_SIZE-1)) { - buffer[i] = ' '; - i++; - } - firstInLine = 0; - } - done: - buffer[i] = 0; - - /* - * Parse the fields, which are: id, width, height, maxIntensity. - */ - - if (strncmp(buffer, "P6 ", 3) == 0) { - type = PPM; - } else if (strncmp(buffer, "P5 ", 3) == 0) { - type = PGM; - } else { - return 0; - } - if (sscanf(buffer+3, "%d %d %d", widthPtr, heightPtr, maxIntensityPtr) - != 3) { - return 0; - } - return type; -} diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c deleted file mode 100644 index 1f3aaea..0000000 --- a/generic/tkImgPhoto.c +++ /dev/null @@ -1,4144 +0,0 @@ -/* - * tkImgPhoto.c -- - * - * Implements images of type "photo" for Tk. Photo images are - * stored in full color (24 bits per pixel) and displayed using - * dithering if necessary. - * - * Copyright (c) 1994 The Australian National University. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * Author: Paul Mackerras (paulus@cs.anu.edu.au), - * Department of Computer Science, - * Australian National University. - * - * RCS: @(#) $Id: tkImgPhoto.c,v 1.2 1998/09/14 18:23:13 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" -#include "tclMath.h" -#include <ctype.h> - -/* - * Declaration for internal Xlib function used here: - */ - -extern _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image)); - -/* - * A signed 8-bit integral type. If chars are unsigned and the compiler - * isn't an ANSI one, then we have to use short instead (which wastes - * space) to get signed behavior. - */ - -#if defined(__STDC__) || defined(_AIX) - typedef signed char schar; -#else -# ifndef __CHAR_UNSIGNED__ - typedef char schar; -# else - typedef short schar; -# endif -#endif - -/* - * An unsigned 32-bit integral type, used for pixel values. - * We use int rather than long here to accommodate those systems - * where longs are 64 bits. - */ - -typedef unsigned int pixel; - -/* - * The maximum number of pixels to transmit to the server in a - * single XPutImage call. - */ - -#define MAX_PIXELS 65536 - -/* - * The set of colors required to display a photo image in a window depends on: - * - the visual used by the window - * - the palette, which specifies how many levels of each primary - * color to use, and - * - the gamma value for the image. - * - * Pixel values allocated for specific colors are valid only for the - * colormap in which they were allocated. Sets of pixel values - * allocated for displaying photos are re-used in other windows if - * possible, that is, if the display, colormap, palette and gamma - * values match. A hash table is used to locate these sets of pixel - * values, using the following data structure as key: - */ - -typedef struct { - Display *display; /* Qualifies the colormap resource ID */ - Colormap colormap; /* Colormap that the windows are using. */ - double gamma; /* Gamma exponent value for images. */ - Tk_Uid palette; /* Specifies how many shades of each primary - * we want to allocate. */ -} ColorTableId; - -/* - * For a particular (display, colormap, palette, gamma) combination, - * a data structure of the following type is used to store the allocated - * pixel values and other information: - */ - -typedef struct ColorTable { - ColorTableId id; /* Information used in selecting this - * color table. */ - int flags; /* See below. */ - int refCount; /* Number of instances using this map. */ - int liveRefCount; /* Number of instances which are actually - * in use, using this map. */ - int numColors; /* Number of colors allocated for this map. */ - - XVisualInfo visualInfo; /* Information about the visual for windows - * using this color table. */ - - pixel redValues[256]; /* Maps 8-bit values of red intensity - * to a pixel value or index in pixelMap. */ - pixel greenValues[256]; /* Ditto for green intensity */ - pixel blueValues[256]; /* Ditto for blue intensity */ - unsigned long *pixelMap; /* Actual pixel values allocated. */ - - unsigned char colorQuant[3][256]; - /* Maps 8-bit intensities to quantized - * intensities. The first index is 0 for - * red, 1 for green, 2 for blue. */ -} ColorTable; - -/* - * Bit definitions for the flags field of a ColorTable. - * BLACK_AND_WHITE: 1 means only black and white colors are - * available. - * COLOR_WINDOW: 1 means a full 3-D color cube has been - * allocated. - * DISPOSE_PENDING: 1 means a call to DisposeColorTable has - * been scheduled as an idle handler, but it - * hasn't been invoked yet. - * MAP_COLORS: 1 means pixel values should be mapped - * through pixelMap. - */ - -#define BLACK_AND_WHITE 1 -#define COLOR_WINDOW 2 -#define DISPOSE_PENDING 4 -#define MAP_COLORS 8 - -/* - * Definition of the data associated with each photo image master. - */ - -typedef struct PhotoMaster { - Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means - * the image is being deleted. */ - Tcl_Interp *interp; /* Interpreter associated with the - * application using this image. */ - Tcl_Command imageCmd; /* Token for image command (used to delete - * it when the image goes away). NULL means - * the image command has already been - * deleted. */ - int flags; /* Sundry flags, defined below. */ - int width, height; /* Dimensions of image. */ - int userWidth, userHeight; /* User-declared image dimensions. */ - Tk_Uid palette; /* User-specified default palette for - * instances of this image. */ - double gamma; /* Display gamma value to correct for. */ - char *fileString; /* Name of file to read into image. */ - char *dataString; /* String value to use as contents of image. */ - char *format; /* User-specified format of data in image - * file or string value. */ - unsigned char *pix24; /* Local storage for 24-bit image. */ - int ditherX, ditherY; /* Location of first incorrectly - * dithered pixel in image. */ - TkRegion validRegion; /* Tk region indicating which parts of - * the image have valid image data. */ - struct PhotoInstance *instancePtr; - /* First in the list of instances - * associated with this master. */ -} PhotoMaster; - -/* - * Bit definitions for the flags field of a PhotoMaster. - * COLOR_IMAGE: 1 means that the image has different color - * components. - * IMAGE_CHANGED: 1 means that the instances of this image - * need to be redithered. - */ - -#define COLOR_IMAGE 1 -#define IMAGE_CHANGED 2 - -/* - * The following data structure represents all of the instances of - * a photo image in windows on a given screen that are using the - * same colormap. - */ - -typedef struct PhotoInstance { - PhotoMaster *masterPtr; /* Pointer to master for image. */ - Display *display; /* Display for windows using this instance. */ - Colormap colormap; /* The image may only be used in windows with - * this particular colormap. */ - struct PhotoInstance *nextPtr; - /* Pointer to the next instance in the list - * of instances associated with this master. */ - int refCount; /* Number of instances using this structure. */ - Tk_Uid palette; /* Palette for these particular instances. */ - double gamma; /* Gamma value for these instances. */ - Tk_Uid defaultPalette; /* Default palette to use if a palette - * is not specified for the master. */ - ColorTable *colorTablePtr; /* Pointer to information about colors - * allocated for image display in windows - * like this one. */ - Pixmap pixels; /* X pixmap containing dithered image. */ - int width, height; /* Dimensions of the pixmap. */ - schar *error; /* Error image, used in dithering. */ - XImage *imagePtr; /* Image structure for converted pixels. */ - XVisualInfo visualInfo; /* Information about the visual that these - * windows are using. */ - GC gc; /* Graphics context for writing images - * to the pixmap. */ -} PhotoInstance; - -/* - * The following data structure is used to return information - * from ParseSubcommandOptions: - */ - -struct SubcommandOptions { - int options; /* Individual bits indicate which - * options were specified - see below. */ - char *name; /* Name specified without an option. */ - int fromX, fromY; /* Values specified for -from option. */ - int fromX2, fromY2; /* Second coordinate pair for -from option. */ - int toX, toY; /* Values specified for -to option. */ - int toX2, toY2; /* Second coordinate pair for -to option. */ - int zoomX, zoomY; /* Values specified for -zoom option. */ - int subsampleX, subsampleY; /* Values specified for -subsample option. */ - char *format; /* Value specified for -format option. */ -}; - -/* - * Bit definitions for use with ParseSubcommandOptions: - * Each bit is set in the allowedOptions parameter on a call to - * ParseSubcommandOptions if that option is allowed for the current - * photo image subcommand. On return, the bit is set in the options - * field of the SubcommandOptions structure if that option was specified. - * - * OPT_FORMAT: Set if -format option allowed/specified. - * OPT_FROM: Set if -from option allowed/specified. - * OPT_SHRINK: Set if -shrink option allowed/specified. - * OPT_SUBSAMPLE: Set if -subsample option allowed/spec'd. - * OPT_TO: Set if -to option allowed/specified. - * OPT_ZOOM: Set if -zoom option allowed/specified. - */ - -#define OPT_FORMAT 1 -#define OPT_FROM 2 -#define OPT_SHRINK 4 -#define OPT_SUBSAMPLE 8 -#define OPT_TO 0x10 -#define OPT_ZOOM 0x20 - -/* - * List of option names. The order here must match the order of - * declarations of the OPT_* constants above. - */ - -static char *optionNames[] = { - "-format", - "-from", - "-shrink", - "-subsample", - "-to", - "-zoom", - (char *) NULL -}; - -/* - * The type record for photo images: - */ - -static int ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int argc, char **argv, - Tk_ImageType *typePtr, Tk_ImageMaster master, - ClientData *clientDataPtr)); -static ClientData ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin, - ClientData clientData)); -static void ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData, - Display *display, Drawable drawable, - int imageX, int imageY, int width, int height, - int drawableX, int drawableY)); -static void ImgPhotoFree _ANSI_ARGS_((ClientData clientData, - Display *display)); -static void ImgPhotoDelete _ANSI_ARGS_((ClientData clientData)); - -Tk_ImageType tkPhotoImageType = { - "photo", /* name */ - ImgPhotoCreate, /* createProc */ - ImgPhotoGet, /* getProc */ - ImgPhotoDisplay, /* displayProc */ - ImgPhotoFree, /* freeProc */ - ImgPhotoDelete, /* deleteProc */ - (Tk_ImageType *) NULL /* nextPtr */ -}; - -/* - * Default configuration - */ - -#define DEF_PHOTO_GAMMA "1" -#define DEF_PHOTO_HEIGHT "0" -#define DEF_PHOTO_PALETTE "" -#define DEF_PHOTO_WIDTH "0" - -/* - * Information used for parsing configuration specifications: - */ -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PhotoMaster, dataString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-format", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PhotoMaster, format), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL, - DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0}, - {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL, - DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0}, - {TK_CONFIG_UID, "-palette", (char *) NULL, (char *) NULL, - DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0}, - {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL, - DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Hash table used to hash from (display, colormap, palette, gamma) - * to ColorTable address. - */ - -static Tcl_HashTable imgPhotoColorHash; -static int imgPhotoColorHashInitialized; -#define N_COLOR_HASH (sizeof(ColorTableId) / sizeof(int)) - -/* - * Pointer to the first in the list of known photo image formats. - */ - -static Tk_PhotoImageFormat *formatList = NULL; - -/* - * Forward declarations - */ - -static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static int ParseSubcommandOptions _ANSI_ARGS_(( - struct SubcommandOptions *optPtr, - Tcl_Interp *interp, int allowedOptions, - int *indexPtr, int argc, char **argv)); -static void ImgPhotoCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static int ImgPhotoConfigureMaster _ANSI_ARGS_(( - Tcl_Interp *interp, PhotoMaster *masterPtr, - int argc, char **argv, int flags)); -static void ImgPhotoConfigureInstance _ANSI_ARGS_(( - PhotoInstance *instancePtr)); -static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr, - int width, int height)); -static void ImgPhotoInstanceSetSize _ANSI_ARGS_(( - PhotoInstance *instancePtr)); -static int IsValidPalette _ANSI_ARGS_((PhotoInstance *instancePtr, - char *palette)); -static int CountBits _ANSI_ARGS_((pixel mask)); -static void GetColorTable _ANSI_ARGS_((PhotoInstance *instancePtr)); -static void FreeColorTable _ANSI_ARGS_((ColorTable *colorPtr)); -static void AllocateColors _ANSI_ARGS_((ColorTable *colorPtr)); -static void DisposeColorTable _ANSI_ARGS_((ClientData clientData)); -static void DisposeInstance _ANSI_ARGS_((ClientData clientData)); -static int ReclaimColors _ANSI_ARGS_((ColorTableId *id, - int numColors)); -static int MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, - char *formatString, - Tk_PhotoImageFormat **imageFormatPtr, - int *widthPtr, int *heightPtr)); -static int MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp, - char *string, char *formatString, - Tk_PhotoImageFormat **imageFormatPtr, - int *widthPtr, int *heightPtr)); -static void Dither _ANSI_ARGS_((PhotoMaster *masterPtr, - int x, int y, int width, int height)); -static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr, - int x, int y, int width, int height)); - -#undef MIN -#define MIN(a, b) ((a) < (b)? (a): (b)) -#undef MAX -#define MAX(a, b) ((a) > (b)? (a): (b)) - -/* - *---------------------------------------------------------------------- - * - * Tk_CreatePhotoImageFormat -- - * - * This procedure is invoked by an image file handler to register - * a new photo image format and the procedures that handle the - * new format. The procedure is typically invoked during - * Tcl_AppInit. - * - * Results: - * None. - * - * Side effects: - * The new image file format is entered into a table used in the - * photo image "read" and "write" subcommands. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CreatePhotoImageFormat(formatPtr) - Tk_PhotoImageFormat *formatPtr; - /* Structure describing the format. All of - * the fields except "nextPtr" must be filled - * in by caller. Must not have been passed - * to Tk_CreatePhotoImageFormat previously. */ -{ - Tk_PhotoImageFormat *copyPtr; - - copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat)); - *copyPtr = *formatPtr; - copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1)); - strcpy(copyPtr->name, formatPtr->name); - copyPtr->nextPtr = formatList; - formatList = copyPtr; -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoCreate -- - * - * This procedure is called by the Tk image code to create - * a new photo image. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * The data structure for a new photo image is allocated and - * initialized. - * - *---------------------------------------------------------------------- - */ - -static int -ImgPhotoCreate(interp, name, argc, argv, typePtr, master, clientDataPtr) - Tcl_Interp *interp; /* Interpreter for application containing - * image. */ - char *name; /* Name to use for image. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings for options (doesn't - * include image name or type). */ - Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ - Tk_ImageMaster master; /* Token for image, to be used by us in - * later callbacks. */ - ClientData *clientDataPtr; /* Store manager's token for image here; - * it will be returned in later callbacks. */ -{ - PhotoMaster *masterPtr; - - /* - * Allocate and initialize the photo image master record. - */ - - masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster)); - memset((void *) masterPtr, 0, sizeof(PhotoMaster)); - masterPtr->tkMaster = master; - masterPtr->interp = interp; - masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgPhotoCmd, - (ClientData) masterPtr, ImgPhotoCmdDeletedProc); - masterPtr->palette = NULL; - masterPtr->pix24 = NULL; - masterPtr->instancePtr = NULL; - masterPtr->validRegion = TkCreateRegion(); - - /* - * Process configuration options given in the image create command. - */ - - if (ImgPhotoConfigureMaster(interp, masterPtr, argc, argv, 0) != TCL_OK) { - ImgPhotoDelete((ClientData) masterPtr); - return TCL_ERROR; - } - - *clientDataPtr = (ClientData) masterPtr; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoCmd -- - * - * This procedure is invoked to process the Tcl command that - * corresponds to a photo image. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -static int -ImgPhotoCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about photo master. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - PhotoMaster *masterPtr = (PhotoMaster *) clientData; - int c, result, index; - int x, y, width, height; - int dataWidth, dataHeight; - struct SubcommandOptions options; - int listArgc; - char **listArgv; - char **srcArgv; - unsigned char *pixelPtr; - Tk_PhotoImageBlock block; - Tk_Window tkwin; - char string[16]; - XColor color; - Tk_PhotoImageFormat *imageFormat; - int imageWidth, imageHeight; - int matched; - Tcl_Channel chan; - Tk_PhotoHandle srcHandle; - size_t length; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - - if ((c == 'b') && (strncmp(argv[1], "blank", length) == 0)) { - /* - * photo blank command - just call Tk_PhotoBlank. - */ - - if (argc == 2) { - Tk_PhotoBlank(masterPtr); - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " blank\"", (char *) NULL); - return TCL_ERROR; - } - } else if ((c == 'c') && (length >= 2) - && (strncmp(argv[1], "cget", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - return TCL_ERROR; - } - Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, - (char *) masterPtr, argv[2], 0); - } else if ((c == 'c') && (length >= 3) - && (strncmp(argv[1], "configure", length) == 0)) { - /* - * photo configure command - handle this in the standard way. - */ - - if (argc == 2) { - return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, (char *) NULL, 0); - } - if (argc == 3) { - return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, argv[2], 0); - } - return ImgPhotoConfigureMaster(interp, masterPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } else if ((c == 'c') && (length >= 3) - && (strncmp(argv[1], "copy", length) == 0)) { - /* - * photo copy command - first parse options. - */ - - index = 2; - memset((VOID *) &options, 0, sizeof(options)); - options.zoomX = options.zoomY = 1; - options.subsampleX = options.subsampleY = 1; - options.name = NULL; - if (ParseSubcommandOptions(&options, interp, - OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK, - &index, argc, argv) != TCL_OK) { - return TCL_ERROR; - } - if (options.name == NULL || index < argc) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " copy source-image ?-from x1 y1 x2 y2?", - " ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?", - "\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Look for the source image and get a pointer to its image data. - * Check the values given for the -from option. - */ - - if ((srcHandle = Tk_FindPhoto(interp, options.name)) == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't", - " exist or is not a photo image", (char *) NULL); - return TCL_ERROR; - } - Tk_PhotoGetImage(srcHandle, &block); - if ((options.fromX2 > block.width) || (options.fromY2 > block.height) - || (options.fromX2 > block.width) - || (options.fromY2 > block.height)) { - Tcl_AppendResult(interp, "coordinates for -from option extend ", - "outside source image", (char *) NULL); - return TCL_ERROR; - } - - /* - * Fill in default values for unspecified parameters. - */ - - if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) { - options.fromX2 = block.width; - options.fromY2 = block.height; - } - if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) { - width = options.fromX2 - options.fromX; - if (options.subsampleX > 0) { - width = (width + options.subsampleX - 1) / options.subsampleX; - } else if (options.subsampleX == 0) { - width = 0; - } else { - width = (width - options.subsampleX - 1) / -options.subsampleX; - } - options.toX2 = options.toX + width * options.zoomX; - - height = options.fromY2 - options.fromY; - if (options.subsampleY > 0) { - height = (height + options.subsampleY - 1) - / options.subsampleY; - } else if (options.subsampleY == 0) { - height = 0; - } else { - height = (height - options.subsampleY - 1) - / -options.subsampleY; - } - options.toY2 = options.toY + height * options.zoomY; - } - - /* - * Set the destination image size if the -shrink option was specified. - */ - - if (options.options & OPT_SHRINK) { - ImgPhotoSetSize(masterPtr, options.toX2, options.toY2); - } - - /* - * Copy the image data over using Tk_PhotoPutZoomedBlock. - */ - - block.pixelPtr += options.fromX * block.pixelSize - + options.fromY * block.pitch; - block.width = options.fromX2 - options.fromX; - block.height = options.fromY2 - options.fromY; - Tk_PhotoPutZoomedBlock((Tk_PhotoHandle) masterPtr, &block, - options.toX, options.toY, options.toX2 - options.toX, - options.toY2 - options.toY, options.zoomX, options.zoomY, - options.subsampleX, options.subsampleY); - - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - /* - * photo get command - first parse and check parameters. - */ - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " get x y\"", (char *) NULL); - return TCL_ERROR; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - return TCL_ERROR; - } - if ((x < 0) || (x >= masterPtr->width) - || (y < 0) || (y >= masterPtr->height)) { - Tcl_AppendResult(interp, argv[0], " get: ", - "coordinates out of range", (char *) NULL); - return TCL_ERROR; - } - - /* - * Extract the value of the desired pixel and format it as a string. - */ - - pixelPtr = masterPtr->pix24 + (y * masterPtr->width + x) * 3; - sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1], - pixelPtr[2]); - Tcl_AppendResult(interp, string, (char *) NULL); - } else if ((c == 'p') && (strncmp(argv[1], "put", length) == 0)) { - /* - * photo put command - first parse the options and colors specified. - */ - - index = 2; - memset((VOID *) &options, 0, sizeof(options)); - options.name = NULL; - if (ParseSubcommandOptions(&options, interp, OPT_TO, - &index, argc, argv) != TCL_OK) { - return TCL_ERROR; - } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " put {{colors...}...} ?-to x1 y1 x2 y2?\"", - (char *) NULL); - return TCL_ERROR; - } - if (Tcl_SplitList(interp, options.name, &dataHeight, &srcArgv) - != TCL_OK) { - return TCL_ERROR; - } - tkwin = Tk_MainWindow(interp); - block.pixelPtr = NULL; - dataWidth = 0; - pixelPtr = NULL; - for (y = 0; y < dataHeight; ++y) { - if (Tcl_SplitList(interp, srcArgv[y], &listArgc, &listArgv) - != TCL_OK) { - break; - } - if (y == 0) { - dataWidth = listArgc; - pixelPtr = (unsigned char *) ckalloc((unsigned) - dataWidth * dataHeight * 3); - block.pixelPtr = pixelPtr; - } else { - if (listArgc != dataWidth) { - Tcl_AppendResult(interp, "all elements of color list must", - " have the same number of elements", - (char *) NULL); - ckfree((char *) listArgv); - break; - } - } - for (x = 0; x < dataWidth; ++x) { - if (!XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), - listArgv[x], &color)) { - Tcl_AppendResult(interp, "can't parse color \"", - listArgv[x], "\"", (char *) NULL); - break; - } - *pixelPtr++ = color.red >> 8; - *pixelPtr++ = color.green >> 8; - *pixelPtr++ = color.blue >> 8; - } - ckfree((char *) listArgv); - if (x < dataWidth) - break; - } - ckfree((char *) srcArgv); - if (y < dataHeight || dataHeight == 0 || dataWidth == 0) { - if (block.pixelPtr != NULL) { - ckfree((char *) block.pixelPtr); - } - if (y < dataHeight) { - return TCL_ERROR; - } - return TCL_OK; - } - - /* - * Fill in default values for the -to option, then - * copy the block in using Tk_PhotoPutBlock. - */ - - if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) { - options.toX2 = options.toX + dataWidth; - options.toY2 = options.toY + dataHeight; - } - block.width = dataWidth; - block.height = dataHeight; - block.pitch = dataWidth * 3; - block.pixelSize = 3; - block.offset[0] = 0; - block.offset[1] = 1; - block.offset[2] = 2; - Tk_PhotoPutBlock((ClientData)masterPtr, &block, - options.toX, options.toY, options.toX2 - options.toX, - options.toY2 - options.toY); - ckfree((char *) block.pixelPtr); - } else if ((c == 'r') && (length >= 3) - && (strncmp(argv[1], "read", length) == 0)) { - /* - * photo read command - first parse the options specified. - */ - - index = 2; - memset((VOID *) &options, 0, sizeof(options)); - options.name = NULL; - options.format = NULL; - if (ParseSubcommandOptions(&options, interp, - OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK, - &index, argc, argv) != TCL_OK) { - return TCL_ERROR; - } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " read fileName ?-format format-name?", - " ?-from x1 y1 x2 y2? ?-to x y? ?-shrink?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Prevent file system access in safe interpreters. - */ - - if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't get image from a file in a", - " safe interpreter", (char *) NULL); - return TCL_ERROR; - } - - /* - * Open the image file and look for a handler for it. - */ - - chan = Tcl_OpenFileChannel(interp, options.name, "r", 0); - if (chan == NULL) { - return TCL_ERROR; - } - if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") - != TCL_OK) { - return TCL_ERROR; - } - if (MatchFileFormat(interp, chan, options.name, options.format, - &imageFormat, &imageWidth, &imageHeight) != TCL_OK) { - Tcl_Close(NULL, chan); - return TCL_ERROR; - } - - /* - * Check the values given for the -from option. - */ - - if ((options.fromX > imageWidth) || (options.fromY > imageHeight) - || (options.fromX2 > imageWidth) - || (options.fromY2 > imageHeight)) { - Tcl_AppendResult(interp, "coordinates for -from option extend ", - "outside source image", (char *) NULL); - Tcl_Close(NULL, chan); - return TCL_ERROR; - } - if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) { - width = imageWidth - options.fromX; - height = imageHeight - options.fromY; - } else { - width = options.fromX2 - options.fromX; - height = options.fromY2 - options.fromY; - } - - /* - * If the -shrink option was specified, set the size of the image. - */ - - if (options.options & OPT_SHRINK) { - ImgPhotoSetSize(masterPtr, options.toX + width, - options.toY + height); - } - - /* - * Call the handler's file read procedure to read the data - * into the image. - */ - - result = (*imageFormat->fileReadProc)(interp, chan, options.name, - options.format, (Tk_PhotoHandle) masterPtr, options.toX, - options.toY, width, height, options.fromX, options.fromY); - if (chan != NULL) { - Tcl_Close(NULL, chan); - } - return result; - } else if ((c == 'r') && (length >= 3) - && (strncmp(argv[1], "redither", length) == 0)) { - - if (argc == 2) { - /* - * Call Dither if any part of the image is not correctly - * dithered at present. - */ - - x = masterPtr->ditherX; - y = masterPtr->ditherY; - if (masterPtr->ditherX != 0) { - Dither(masterPtr, x, y, masterPtr->width - x, 1); - } - if (masterPtr->ditherY < masterPtr->height) { - x = 0; - Dither(masterPtr, 0, masterPtr->ditherY, masterPtr->width, - masterPtr->height - masterPtr->ditherY); - } - - if (y < masterPtr->height) { - /* - * Tell the core image code that part of the image has changed. - */ - - Tk_ImageChanged(masterPtr->tkMaster, x, y, - (masterPtr->width - x), (masterPtr->height - y), - masterPtr->width, masterPtr->height); - } - - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " redither\"", (char *) NULL); - return TCL_ERROR; - } - } else if ((c == 'w') && (strncmp(argv[1], "write", length) == 0)) { - - /* - * Prevent file system access in safe interpreters. - */ - - if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't write image to a file in a", - " safe interpreter", (char *) NULL); - return TCL_ERROR; - } - - /* - * photo write command - first parse and check any options given. - */ - - index = 2; - memset((VOID *) &options, 0, sizeof(options)); - options.name = NULL; - options.format = NULL; - if (ParseSubcommandOptions(&options, interp, OPT_FORMAT | OPT_FROM, - &index, argc, argv) != TCL_OK) { - return TCL_ERROR; - } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " write fileName ?-format format-name?", - "?-from x1 y1 x2 y2?\"", (char *) NULL); - return TCL_ERROR; - } - if ((options.fromX > masterPtr->width) - || (options.fromY > masterPtr->height) - || (options.fromX2 > masterPtr->width) - || (options.fromY2 > masterPtr->height)) { - Tcl_AppendResult(interp, "coordinates for -from option extend ", - "outside image", (char *) NULL); - return TCL_ERROR; - } - - /* - * Fill in default values for unspecified parameters. - */ - - if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) { - options.fromX2 = masterPtr->width; - options.fromY2 = masterPtr->height; - } - - /* - * Search for an appropriate image file format handler, - * and give an error if none is found. - */ - - matched = 0; - for (imageFormat = formatList; imageFormat != NULL; - imageFormat = imageFormat->nextPtr) { - if ((options.format == NULL) - || (strncasecmp(options.format, imageFormat->name, - strlen(imageFormat->name)) == 0)) { - matched = 1; - if (imageFormat->fileWriteProc != NULL) { - break; - } - } - } - if (imageFormat == NULL) { - if (options.format == NULL) { - Tcl_AppendResult(interp, "no available image file format ", - "has file writing capability", (char *) NULL); - } else if (!matched) { - Tcl_AppendResult(interp, "image file format \"", - options.format, "\" is unknown", (char *) NULL); - } else { - Tcl_AppendResult(interp, "image file format \"", - options.format, "\" has no file writing capability", - (char *) NULL); - } - return TCL_ERROR; - } - - /* - * Call the handler's file write procedure to write out - * the image. - */ - - Tk_PhotoGetImage((Tk_PhotoHandle) masterPtr, &block); - block.pixelPtr += options.fromY * block.pitch + options.fromX * 3; - block.width = options.fromX2 - options.fromX; - block.height = options.fromY2 - options.fromY; - return (*imageFormat->fileWriteProc)(interp, options.name, - options.format, &block); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be blank, cget, configure, copy, get, put,", - " read, redither, or write", (char *) NULL); - return TCL_ERROR; - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ParseSubcommandOptions -- - * - * This procedure is invoked to process one of the options - * which may be specified for the photo image subcommands, - * namely, -from, -to, -zoom, -subsample, -format, and -shrink. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Fields in *optPtr get filled in. - * - *---------------------------------------------------------------------- - */ - -static int -ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) - struct SubcommandOptions *optPtr; - /* Information about the options specified - * and the values given is returned here. */ - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - int allowedOptions; /* Indicates which options are valid for - * the current command. */ - int *optIndexPtr; /* Points to a variable containing the - * current index in argv; this variable is - * updated by this procedure. */ - int argc; /* Number of arguments in argv[]. */ - char **argv; /* Arguments to be parsed. */ -{ - int index, c, bit, currentBit; - size_t length; - char *option, **listPtr; - int values[4]; - int numValues, maxValues, argIndex; - - for (index = *optIndexPtr; index < argc; *optIndexPtr = ++index) { - /* - * We can have one value specified without an option; - * it goes into optPtr->name. - */ - - option = argv[index]; - if (option[0] != '-') { - if (optPtr->name == NULL) { - optPtr->name = option; - continue; - } - break; - } - - /* - * Work out which option this is. - */ - - length = strlen(option); - c = option[0]; - bit = 0; - currentBit = 1; - for (listPtr = optionNames; *listPtr != NULL; ++listPtr) { - if ((c == *listPtr[0]) - && (strncmp(option, *listPtr, length) == 0)) { - if (bit != 0) { - bit = 0; /* An ambiguous option. */ - break; - } - bit = currentBit; - } - currentBit <<= 1; - } - - /* - * If this option is not recognized and allowed, put - * an error message in the interpreter and return. - */ - - if ((allowedOptions & bit) == 0) { - Tcl_AppendResult(interp, "unrecognized option \"", argv[index], - "\": must be ", (char *)NULL); - bit = 1; - for (listPtr = optionNames; *listPtr != NULL; ++listPtr) { - if ((allowedOptions & bit) != 0) { - if ((allowedOptions & (bit - 1)) != 0) { - Tcl_AppendResult(interp, ", ", (char *) NULL); - if ((allowedOptions & ~((bit << 1) - 1)) == 0) { - Tcl_AppendResult(interp, "or ", (char *) NULL); - } - } - Tcl_AppendResult(interp, *listPtr, (char *) NULL); - } - bit <<= 1; - } - return TCL_ERROR; - } - - /* - * For the -from, -to, -zoom and -subsample options, - * parse the values given. Report an error if too few - * or too many values are given. - */ - - if ((bit != OPT_SHRINK) && (bit != OPT_FORMAT)) { - maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2; - argIndex = index + 1; - for (numValues = 0; numValues < maxValues; ++numValues) { - if ((argIndex < argc) && (isdigit(UCHAR(argv[argIndex][0])) - || ((argv[argIndex][0] == '-') - && (isdigit(UCHAR(argv[argIndex][1])))))) { - if (Tcl_GetInt(interp, argv[argIndex], &values[numValues]) - != TCL_OK) { - return TCL_ERROR; - } - } else { - break; - } - ++argIndex; - } - - if (numValues == 0) { - Tcl_AppendResult(interp, "the \"", argv[index], "\" option ", - "requires one ", maxValues == 2? "or two": "to four", - " integer values", (char *) NULL); - return TCL_ERROR; - } - *optIndexPtr = (index += numValues); - - /* - * Y values default to the corresponding X value if not specified. - */ - - if (numValues == 1) { - values[1] = values[0]; - } - if (numValues == 3) { - values[3] = values[2]; - } - - /* - * Check the values given and put them in the appropriate - * field of the SubcommandOptions structure. - */ - - switch (bit) { - case OPT_FROM: - if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2) - && ((values[2] < 0) || (values[3] < 0)))) { - Tcl_AppendResult(interp, "value(s) for the -from", - " option must be non-negative", (char *) NULL); - return TCL_ERROR; - } - if (numValues <= 2) { - optPtr->fromX = values[0]; - optPtr->fromY = values[1]; - optPtr->fromX2 = -1; - optPtr->fromY2 = -1; - } else { - optPtr->fromX = MIN(values[0], values[2]); - optPtr->fromY = MIN(values[1], values[3]); - optPtr->fromX2 = MAX(values[0], values[2]); - optPtr->fromY2 = MAX(values[1], values[3]); - } - break; - case OPT_SUBSAMPLE: - optPtr->subsampleX = values[0]; - optPtr->subsampleY = values[1]; - break; - case OPT_TO: - if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2) - && ((values[2] < 0) || (values[3] < 0)))) { - Tcl_AppendResult(interp, "value(s) for the -to", - " option must be non-negative", (char *) NULL); - return TCL_ERROR; - } - if (numValues <= 2) { - optPtr->toX = values[0]; - optPtr->toY = values[1]; - optPtr->toX2 = -1; - optPtr->toY2 = -1; - } else { - optPtr->toX = MIN(values[0], values[2]); - optPtr->toY = MIN(values[1], values[3]); - optPtr->toX2 = MAX(values[0], values[2]); - optPtr->toY2 = MAX(values[1], values[3]); - } - break; - case OPT_ZOOM: - if ((values[0] <= 0) || (values[1] <= 0)) { - Tcl_AppendResult(interp, "value(s) for the -zoom", - " option must be positive", (char *) NULL); - return TCL_ERROR; - } - optPtr->zoomX = values[0]; - optPtr->zoomY = values[1]; - break; - } - } else if (bit == OPT_FORMAT) { - /* - * The -format option takes a single string value. - */ - - if (index + 1 < argc) { - *optIndexPtr = ++index; - optPtr->format = argv[index]; - } else { - Tcl_AppendResult(interp, "the \"-format\" option ", - "requires a value", (char *) NULL); - return TCL_ERROR; - } - } - - /* - * Remember that we saw this option. - */ - - optPtr->options |= bit; - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoConfigureMaster -- - * - * This procedure is called when a photo image is created or - * reconfigured. It processes configuration options and resets - * any instances of the image. - * - * Results: - * A standard Tcl return value. If TCL_ERROR is returned then - * an error message is left in masterPtr->interp->result. - * - * Side effects: - * Existing instances of the image will be redisplayed to match - * the new configuration options. - * - *---------------------------------------------------------------------- - */ - -static int -ImgPhotoConfigureMaster(interp, masterPtr, argc, argv, flags) - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - PhotoMaster *masterPtr; /* Pointer to data structure describing - * overall photo image to (re)configure. */ - int argc; /* Number of entries in argv. */ - char **argv; /* Pairs of configuration options for image. */ - int flags; /* Flags to pass to Tk_ConfigureWidget, - * such as TK_CONFIG_ARGV_ONLY. */ -{ - PhotoInstance *instancePtr; - char *oldFileString, *oldDataString, *oldPaletteString; - double oldGamma; - int result; - Tcl_Channel chan; - Tk_PhotoImageFormat *imageFormat; - int imageWidth, imageHeight; - - /* - * Save the current values for fileString and dataString, so we - * can tell if the user specifies them anew. - */ - - oldFileString = masterPtr->fileString; - oldDataString = (oldFileString == NULL)? masterPtr->dataString: NULL; - oldPaletteString = masterPtr->palette; - oldGamma = masterPtr->gamma; - - /* - * Process the configuration options specified. - */ - - if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs, - argc, argv, (char *) masterPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Regard the empty string for -file, -data or -format as the null - * value. - */ - - if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) { - ckfree(masterPtr->fileString); - masterPtr->fileString = NULL; - } - if ((masterPtr->dataString != NULL) && (masterPtr->dataString[0] == 0)) { - ckfree(masterPtr->dataString); - masterPtr->dataString = NULL; - } - if ((masterPtr->format != NULL) && (masterPtr->format[0] == 0)) { - ckfree(masterPtr->format); - masterPtr->format = NULL; - } - - /* - * Set the image to the user-requested size, if any, - * and make sure storage is correctly allocated for this image. - */ - - ImgPhotoSetSize(masterPtr, masterPtr->width, masterPtr->height); - - /* - * Read in the image from the file or string if the user has - * specified the -file or -data option. - */ - - if ((masterPtr->fileString != NULL) - && (masterPtr->fileString != oldFileString)) { - - /* - * Prevent file system access in a safe interpreter. - */ - - if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't get image from a file in a", - " safe interpreter", (char *) NULL); - return TCL_ERROR; - } - - chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0); - if (chan == NULL) { - return TCL_ERROR; - } - if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") - != TCL_OK) { - return TCL_ERROR; - } - if (MatchFileFormat(interp, chan, masterPtr->fileString, - masterPtr->format, &imageFormat, &imageWidth, - &imageHeight) != TCL_OK) { - Tcl_Close(NULL, chan); - return TCL_ERROR; - } - ImgPhotoSetSize(masterPtr, imageWidth, imageHeight); - result = (*imageFormat->fileReadProc)(interp, chan, - masterPtr->fileString, masterPtr->format, - (Tk_PhotoHandle) masterPtr, 0, 0, - imageWidth, imageHeight, 0, 0); - Tcl_Close(NULL, chan); - if (result != TCL_OK) { - return TCL_ERROR; - } - - masterPtr->flags |= IMAGE_CHANGED; - } - - if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL) - && (masterPtr->dataString != oldDataString)) { - - if (MatchStringFormat(interp, masterPtr->dataString, - masterPtr->format, &imageFormat, &imageWidth, - &imageHeight) != TCL_OK) { - return TCL_ERROR; - } - ImgPhotoSetSize(masterPtr, imageWidth, imageHeight); - if ((*imageFormat->stringReadProc)(interp, masterPtr->dataString, - masterPtr->format, (Tk_PhotoHandle) masterPtr, - 0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) { - return TCL_ERROR; - } - - masterPtr->flags |= IMAGE_CHANGED; - } - - /* - * Enforce a reasonable value for gamma. - */ - - if (masterPtr->gamma <= 0) { - masterPtr->gamma = 1.0; - } - - if ((masterPtr->gamma != oldGamma) - || (masterPtr->palette != oldPaletteString)) { - masterPtr->flags |= IMAGE_CHANGED; - } - - /* - * Cycle through all of the instances of this image, regenerating - * the information for each instance. Then force the image to be - * redisplayed everywhere that it is used. - */ - - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - ImgPhotoConfigureInstance(instancePtr); - } - - /* - * Inform the generic image code that the image - * has (potentially) changed. - */ - - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width, - masterPtr->height, masterPtr->width, masterPtr->height); - masterPtr->flags &= ~IMAGE_CHANGED; - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoConfigureInstance -- - * - * This procedure is called to create displaying information for - * a photo image instance based on the configuration information - * in the master. It is invoked both when new instances are - * created and when the master is reconfigured. - * - * Results: - * None. - * - * Side effects: - * Generates errors via Tcl_BackgroundError if there are problems - * in setting up the instance. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoConfigureInstance(instancePtr) - PhotoInstance *instancePtr; /* Instance to reconfigure. */ -{ - PhotoMaster *masterPtr = instancePtr->masterPtr; - XImage *imagePtr; - int bitsPerPixel; - ColorTable *colorTablePtr; - XRectangle validBox; - - /* - * If the -palette configuration option has been set for the master, - * use the value specified for our palette, but only if it is - * a valid palette for our windows. Use the gamma value specified - * the master. - */ - - if ((masterPtr->palette && masterPtr->palette[0]) - && IsValidPalette(instancePtr, masterPtr->palette)) { - instancePtr->palette = masterPtr->palette; - } else { - instancePtr->palette = instancePtr->defaultPalette; - } - instancePtr->gamma = masterPtr->gamma; - - /* - * If we don't currently have a color table, or if the one we - * have no longer applies (e.g. because our palette or gamma - * has changed), get a new one. - */ - - colorTablePtr = instancePtr->colorTablePtr; - if ((colorTablePtr == NULL) - || (instancePtr->colormap != colorTablePtr->id.colormap) - || (instancePtr->palette != colorTablePtr->id.palette) - || (instancePtr->gamma != colorTablePtr->id.gamma)) { - /* - * Free up our old color table, and get a new one. - */ - - if (colorTablePtr != NULL) { - colorTablePtr->liveRefCount -= 1; - FreeColorTable(colorTablePtr); - } - GetColorTable(instancePtr); - - /* - * Create a new XImage structure for sending data to - * the X server, if necessary. - */ - - if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) { - bitsPerPixel = 1; - } else { - bitsPerPixel = instancePtr->visualInfo.depth; - } - - if ((instancePtr->imagePtr == NULL) - || (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) { - if (instancePtr->imagePtr != NULL) { - XFree((char *) instancePtr->imagePtr); - } - imagePtr = XCreateImage(instancePtr->display, - instancePtr->visualInfo.visual, (unsigned) bitsPerPixel, - (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, (char *) NULL, - 1, 1, 32, 0); - instancePtr->imagePtr = imagePtr; - - /* - * Determine the endianness of this machine. - * We create images using the local host's endianness, rather - * than the endianness of the server; otherwise we would have - * to byte-swap any 16 or 32 bit values that we store in the - * image in those situations where the server's endianness - * is different from ours. - */ - - if (imagePtr != NULL) { - union { - int i; - char c[sizeof(int)]; - } kludge; - - imagePtr->bitmap_unit = sizeof(pixel) * NBBY; - kludge.i = 0; - kludge.c[0] = 1; - imagePtr->byte_order = (kludge.i == 1) ? LSBFirst : MSBFirst; - _XInitImageFuncPtrs(imagePtr); - } - } - } - - /* - * If the user has specified a width and/or height for the master - * which is different from our current width/height, set the size - * to the values specified by the user. If we have no pixmap, we - * do this also, since it has the side effect of allocating a - * pixmap for us. - */ - - if ((instancePtr->pixels == None) || (instancePtr->error == NULL) - || (instancePtr->width != masterPtr->width) - || (instancePtr->height != masterPtr->height)) { - ImgPhotoInstanceSetSize(instancePtr); - } - - /* - * Redither this instance if necessary. - */ - - if ((masterPtr->flags & IMAGE_CHANGED) - || (instancePtr->colorTablePtr != colorTablePtr)) { - TkClipBox(masterPtr->validRegion, &validBox); - if ((validBox.width > 0) && (validBox.height > 0)) { - DitherInstance(instancePtr, validBox.x, validBox.y, - validBox.width, validBox.height); - } - } - -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoGet -- - * - * This procedure is called for each use of a photo image in a - * widget. - * - * Results: - * The return value is a token for the instance, which is passed - * back to us in calls to ImgPhotoDisplay and ImgPhotoFree. - * - * Side effects: - * A data structure is set up for the instance (or, an existing - * instance is re-used for the new one). - * - *---------------------------------------------------------------------- - */ - -static ClientData -ImgPhotoGet(tkwin, masterData) - Tk_Window tkwin; /* Window in which the instance will be - * used. */ - ClientData masterData; /* Pointer to our master structure for the - * image. */ -{ - PhotoMaster *masterPtr = (PhotoMaster *) masterData; - PhotoInstance *instancePtr; - Colormap colormap; - int mono, nRed, nGreen, nBlue; - XVisualInfo visualInfo, *visInfoPtr; - XRectangle validBox; - char buf[16]; - int numVisuals; - XColor *white, *black; - XGCValues gcValues; - - /* - * Table of "best" choices for palette for PseudoColor displays - * with between 3 and 15 bits/pixel. - */ - - static int paletteChoice[13][3] = { - /* #red, #green, #blue */ - {2, 2, 2, /* 3 bits, 8 colors */}, - {2, 3, 2, /* 4 bits, 12 colors */}, - {3, 4, 2, /* 5 bits, 24 colors */}, - {4, 5, 3, /* 6 bits, 60 colors */}, - {5, 6, 4, /* 7 bits, 120 colors */}, - {7, 7, 4, /* 8 bits, 198 colors */}, - {8, 10, 6, /* 9 bits, 480 colors */}, - {10, 12, 8, /* 10 bits, 960 colors */}, - {14, 15, 9, /* 11 bits, 1890 colors */}, - {16, 20, 12, /* 12 bits, 3840 colors */}, - {20, 24, 16, /* 13 bits, 7680 colors */}, - {26, 30, 20, /* 14 bits, 15600 colors */}, - {32, 32, 30, /* 15 bits, 30720 colors */} - }; - - /* - * See if there is already an instance for windows using - * the same colormap. If so then just re-use it. - */ - - colormap = Tk_Colormap(tkwin); - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - if ((colormap == instancePtr->colormap) - && (Tk_Display(tkwin) == instancePtr->display)) { - - /* - * Re-use this instance. - */ - - if (instancePtr->refCount == 0) { - /* - * We are resurrecting this instance. - */ - - Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr); - if (instancePtr->colorTablePtr != NULL) { - FreeColorTable(instancePtr->colorTablePtr); - } - GetColorTable(instancePtr); - } - instancePtr->refCount++; - return (ClientData) instancePtr; - } - } - - /* - * The image isn't already in use in a window with the same colormap. - * Make a new instance of the image. - */ - - instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance)); - instancePtr->masterPtr = masterPtr; - instancePtr->display = Tk_Display(tkwin); - instancePtr->colormap = Tk_Colormap(tkwin); - Tk_PreserveColormap(instancePtr->display, instancePtr->colormap); - instancePtr->refCount = 1; - instancePtr->colorTablePtr = NULL; - instancePtr->pixels = None; - instancePtr->error = NULL; - instancePtr->width = 0; - instancePtr->height = 0; - instancePtr->imagePtr = 0; - instancePtr->nextPtr = masterPtr->instancePtr; - masterPtr->instancePtr = instancePtr; - - /* - * Obtain information about the visual and decide on the - * default palette. - */ - - visualInfo.screen = Tk_ScreenNumber(tkwin); - visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin)); - visInfoPtr = XGetVisualInfo(Tk_Display(tkwin), - VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals); - nRed = 2; - nGreen = nBlue = 0; - mono = 1; - if (visInfoPtr != NULL) { - instancePtr->visualInfo = *visInfoPtr; - switch (visInfoPtr->class) { - case DirectColor: - case TrueColor: - nRed = 1 << CountBits(visInfoPtr->red_mask); - nGreen = 1 << CountBits(visInfoPtr->green_mask); - nBlue = 1 << CountBits(visInfoPtr->blue_mask); - mono = 0; - break; - case PseudoColor: - case StaticColor: - if (visInfoPtr->depth > 15) { - nRed = 32; - nGreen = 32; - nBlue = 32; - mono = 0; - } else if (visInfoPtr->depth >= 3) { - int *ip = paletteChoice[visInfoPtr->depth - 3]; - - nRed = ip[0]; - nGreen = ip[1]; - nBlue = ip[2]; - mono = 0; - } - break; - case GrayScale: - case StaticGray: - nRed = 1 << visInfoPtr->depth; - break; - } - XFree((char *) visInfoPtr); - - } else { - panic("ImgPhotoGet couldn't find visual for window"); - } - - sprintf(buf, ((mono) ? "%d": "%d/%d/%d"), nRed, nGreen, nBlue); - instancePtr->defaultPalette = Tk_GetUid(buf); - - /* - * Make a GC with background = black and foreground = white. - */ - - white = Tk_GetColor(masterPtr->interp, tkwin, "white"); - black = Tk_GetColor(masterPtr->interp, tkwin, "black"); - gcValues.foreground = (white != NULL)? white->pixel: - WhitePixelOfScreen(Tk_Screen(tkwin)); - gcValues.background = (black != NULL)? black->pixel: - BlackPixelOfScreen(Tk_Screen(tkwin)); - gcValues.graphics_exposures = False; - instancePtr->gc = Tk_GetGC(tkwin, - GCForeground|GCBackground|GCGraphicsExposures, &gcValues); - - /* - * Set configuration options and finish the initialization of the instance. - */ - - ImgPhotoConfigureInstance(instancePtr); - - /* - * If this is the first instance, must set the size of the image. - */ - - if (instancePtr->nextPtr == NULL) { - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, - masterPtr->width, masterPtr->height); - } - - /* - * Dither the image to fill in this instance's pixmap. - */ - - TkClipBox(masterPtr->validRegion, &validBox); - if ((validBox.width > 0) && (validBox.height > 0)) { - DitherInstance(instancePtr, validBox.x, validBox.y, validBox.width, - validBox.height); - } - - return (ClientData) instancePtr; -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoDisplay -- - * - * This procedure is invoked to draw a photo image. - * - * Results: - * None. - * - * Side effects: - * A portion of the image gets rendered in a pixmap or window. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoDisplay(clientData, display, drawable, imageX, imageY, width, - height, drawableX, drawableY) - ClientData clientData; /* Pointer to PhotoInstance structure for - * for instance to be displayed. */ - Display *display; /* Display on which to draw image. */ - Drawable drawable; /* Pixmap or window in which to draw image. */ - int imageX, imageY; /* Upper-left corner of region within image - * to draw. */ - int width, height; /* Dimensions of region within image to draw. */ - int drawableX, drawableY; /* Coordinates within drawable that - * correspond to imageX and imageY. */ -{ - PhotoInstance *instancePtr = (PhotoInstance *) clientData; - - /* - * If there's no pixmap, it means that an error occurred - * while creating the image instance so it can't be displayed. - */ - - if (instancePtr->pixels == None) { - return; - } - - /* - * masterPtr->region describes which parts of the image contain - * valid data. We set this region as the clip mask for the gc, - * setting its origin appropriately, and use it when drawing the - * image. - */ - - TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion); - XSetClipOrigin(display, instancePtr->gc, drawableX - imageX, - drawableY - imageY); - XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc, - imageX, imageY, (unsigned) width, (unsigned) height, - drawableX, drawableY); - XSetClipMask(display, instancePtr->gc, None); - XSetClipOrigin(display, instancePtr->gc, 0, 0); -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoFree -- - * - * This procedure is called when a widget ceases to use a - * particular instance of an image. We don't actually get - * rid of the instance until later because we may be about - * to get this instance again. - * - * Results: - * None. - * - * Side effects: - * Internal data structures get cleaned up, later. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoFree(clientData, display) - ClientData clientData; /* Pointer to PhotoInstance structure for - * for instance to be displayed. */ - Display *display; /* Display containing window that used image. */ -{ - PhotoInstance *instancePtr = (PhotoInstance *) clientData; - ColorTable *colorPtr; - - instancePtr->refCount -= 1; - if (instancePtr->refCount > 0) { - return; - } - - /* - * There are no more uses of the image within this widget. - * Decrement the count of live uses of its color table, so - * that its colors can be reclaimed if necessary, and - * set up an idle call to free the instance structure. - */ - - colorPtr = instancePtr->colorTablePtr; - if (colorPtr != NULL) { - colorPtr->liveRefCount -= 1; - } - - Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoDelete -- - * - * This procedure is called by the image code to delete the - * master structure for an image. - * - * Results: - * None. - * - * Side effects: - * Resources associated with the image get freed. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoDelete(masterData) - ClientData masterData; /* Pointer to PhotoMaster structure for - * image. Must not have any more instances. */ -{ - PhotoMaster *masterPtr = (PhotoMaster *) masterData; - PhotoInstance *instancePtr; - - while ((instancePtr = masterPtr->instancePtr) != NULL) { - if (instancePtr->refCount > 0) { - panic("tried to delete photo image when instances still exist"); - } - Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr); - DisposeInstance((ClientData) instancePtr); - } - masterPtr->tkMaster = NULL; - if (masterPtr->imageCmd != NULL) { - Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd); - } - if (masterPtr->pix24 != NULL) { - ckfree((char *) masterPtr->pix24); - } - if (masterPtr->validRegion != NULL) { - TkDestroyRegion(masterPtr->validRegion); - } - Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0); - ckfree((char *) masterPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoCmdDeletedProc -- - * - * This procedure is invoked when the image command for an image - * is deleted. It deletes the image. - * - * Results: - * None. - * - * Side effects: - * The image is deleted. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to PhotoMaster structure for - * image. */ -{ - PhotoMaster *masterPtr = (PhotoMaster *) clientData; - - masterPtr->imageCmd = NULL; - if (masterPtr->tkMaster != NULL) { - Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); - } -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoSetSize -- - * - * This procedure reallocates the image storage and instance - * pixmaps for a photo image, as necessary, to change the - * image's size to `width' x `height' pixels. - * - * Results: - * None. - * - * Side effects: - * Storage gets reallocated, for the master and all its instances. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoSetSize(masterPtr, width, height) - PhotoMaster *masterPtr; - int width, height; -{ - unsigned char *newPix24; - int h, offset, pitch; - unsigned char *srcPtr, *destPtr; - XRectangle validBox, clipBox; - TkRegion clipRegion; - PhotoInstance *instancePtr; - - if (masterPtr->userWidth > 0) { - width = masterPtr->userWidth; - } - if (masterPtr->userHeight > 0) { - height = masterPtr->userHeight; - } - - /* - * We have to trim the valid region if it is currently - * larger than the new image size. - */ - - TkClipBox(masterPtr->validRegion, &validBox); - if ((validBox.x + validBox.width > width) - || (validBox.y + validBox.height > height)) { - clipBox.x = 0; - clipBox.y = 0; - clipBox.width = width; - clipBox.height = height; - clipRegion = TkCreateRegion(); - TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion); - TkIntersectRegion(masterPtr->validRegion, clipRegion, - masterPtr->validRegion); - TkDestroyRegion(clipRegion); - TkClipBox(masterPtr->validRegion, &validBox); - } - - if ((width != masterPtr->width) || (height != masterPtr->height) - || (masterPtr->pix24 == NULL)) { - - /* - * Reallocate storage for the 24-bit image and copy - * over valid regions. - */ - - pitch = width * 3; - newPix24 = (unsigned char *) ckalloc((unsigned) (height * pitch)); - - /* - * Zero the new array. The dithering code shouldn't read the - * areas outside validBox, but they might be copied to another - * photo image or written to a file. - */ - - if ((masterPtr->pix24 != NULL) - && ((width == masterPtr->width) || (width == validBox.width))) { - if (validBox.y > 0) { - memset((VOID *) newPix24, 0, (size_t) (validBox.y * pitch)); - } - h = validBox.y + validBox.height; - if (h < height) { - memset((VOID *) (newPix24 + h * pitch), 0, - (size_t) ((height - h) * pitch)); - } - } else { - memset((VOID *) newPix24, 0, (size_t) (height * pitch)); - } - - if (masterPtr->pix24 != NULL) { - - /* - * Copy the common area over to the new array array and - * free the old array. - */ - - if (width == masterPtr->width) { - - /* - * The region to be copied is contiguous. - */ - - offset = validBox.y * pitch; - memcpy((VOID *) (newPix24 + offset), - (VOID *) (masterPtr->pix24 + offset), - (size_t) (validBox.height * pitch)); - - } else if ((validBox.width > 0) && (validBox.height > 0)) { - - /* - * Area to be copied is not contiguous - copy line by line. - */ - - destPtr = newPix24 + (validBox.y * width + validBox.x) * 3; - srcPtr = masterPtr->pix24 + (validBox.y * masterPtr->width - + validBox.x) * 3; - for (h = validBox.height; h > 0; h--) { - memcpy((VOID *) destPtr, (VOID *) srcPtr, - (size_t) (validBox.width * 3)); - destPtr += width * 3; - srcPtr += masterPtr->width * 3; - } - } - - ckfree((char *) masterPtr->pix24); - } - - masterPtr->pix24 = newPix24; - masterPtr->width = width; - masterPtr->height = height; - - /* - * Dithering will be correct up to the end of the last - * pre-existing complete scanline. - */ - - if ((validBox.x > 0) || (validBox.y > 0)) { - masterPtr->ditherX = 0; - masterPtr->ditherY = 0; - } else if (validBox.width == width) { - if ((int) validBox.height < masterPtr->ditherY) { - masterPtr->ditherX = 0; - masterPtr->ditherY = validBox.height; - } - } else { - if ((masterPtr->ditherY > 0) - || ((int) validBox.width < masterPtr->ditherX)) { - masterPtr->ditherX = validBox.width; - masterPtr->ditherY = 0; - } - } - } - - /* - * Now adjust the sizes of the pixmaps for all of the instances. - */ - - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - ImgPhotoInstanceSetSize(instancePtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * ImgPhotoInstanceSetSize -- - * - * This procedure reallocates the instance pixmap and dithering - * error array for a photo instance, as necessary, to change the - * image's size to `width' x `height' pixels. - * - * Results: - * None. - * - * Side effects: - * Storage gets reallocated, here and in the X server. - * - *---------------------------------------------------------------------- - */ - -static void -ImgPhotoInstanceSetSize(instancePtr) - PhotoInstance *instancePtr; /* Instance whose size is to be - * changed. */ -{ - PhotoMaster *masterPtr; - schar *newError; - schar *errSrcPtr, *errDestPtr; - int h, offset; - XRectangle validBox; - Pixmap newPixmap; - - masterPtr = instancePtr->masterPtr; - TkClipBox(masterPtr->validRegion, &validBox); - - if ((instancePtr->width != masterPtr->width) - || (instancePtr->height != masterPtr->height) - || (instancePtr->pixels == None)) { - newPixmap = Tk_GetPixmap(instancePtr->display, - RootWindow(instancePtr->display, - instancePtr->visualInfo.screen), - (masterPtr->width > 0) ? masterPtr->width: 1, - (masterPtr->height > 0) ? masterPtr->height: 1, - instancePtr->visualInfo.depth); - - /* - * The following is a gross hack needed to properly support colormaps - * under Windows. Before the pixels can be copied to the pixmap, - * the relevent colormap must be associated with the drawable. - * Normally we can infer this association from the window that - * was used to create the pixmap. However, in this case we're - * using the root window, so we have to be more explicit. - */ - - TkSetPixmapColormap(newPixmap, instancePtr->colormap); - - if (instancePtr->pixels != None) { - /* - * Copy any common pixels from the old pixmap and free it. - */ - XCopyArea(instancePtr->display, instancePtr->pixels, newPixmap, - instancePtr->gc, validBox.x, validBox.y, - validBox.width, validBox.height, validBox.x, validBox.y); - Tk_FreePixmap(instancePtr->display, instancePtr->pixels); - } - instancePtr->pixels = newPixmap; - } - - if ((instancePtr->width != masterPtr->width) - || (instancePtr->height != masterPtr->height) - || (instancePtr->error == NULL)) { - - newError = (schar *) ckalloc((unsigned) - (masterPtr->height * masterPtr->width * 3 * sizeof(schar))); - - /* - * Zero the new array so that we don't get bogus error values - * propagating into areas we dither later. - */ - - if ((instancePtr->error != NULL) - && ((instancePtr->width == masterPtr->width) - || (validBox.width == masterPtr->width))) { - if (validBox.y > 0) { - memset((VOID *) newError, 0, (size_t) - (validBox.y * masterPtr->width * 3 * sizeof(schar))); - } - h = validBox.y + validBox.height; - if (h < masterPtr->height) { - memset((VOID *) (newError + h * masterPtr->width * 3), 0, - (size_t) ((masterPtr->height - h) - * masterPtr->width * 3 * sizeof(schar))); - } - } else { - memset((VOID *) newError, 0, (size_t) - (masterPtr->height * masterPtr->width * 3 * sizeof(schar))); - } - - if (instancePtr->error != NULL) { - - /* - * Copy the common area over to the new array - * and free the old array. - */ - - if (masterPtr->width == instancePtr->width) { - - offset = validBox.y * masterPtr->width * 3; - memcpy((VOID *) (newError + offset), - (VOID *) (instancePtr->error + offset), - (size_t) (validBox.height - * masterPtr->width * 3 * sizeof(schar))); - - } else if (validBox.width > 0 && validBox.height > 0) { - - errDestPtr = newError - + (validBox.y * masterPtr->width + validBox.x) * 3; - errSrcPtr = instancePtr->error - + (validBox.y * instancePtr->width + validBox.x) * 3; - for (h = validBox.height; h > 0; --h) { - memcpy((VOID *) errDestPtr, (VOID *) errSrcPtr, - validBox.width * 3 * sizeof(schar)); - errDestPtr += masterPtr->width * 3; - errSrcPtr += instancePtr->width * 3; - } - } - ckfree((char *) instancePtr->error); - } - - instancePtr->error = newError; - } - - instancePtr->width = masterPtr->width; - instancePtr->height = masterPtr->height; -} - -/* - *---------------------------------------------------------------------- - * - * IsValidPalette -- - * - * This procedure is called to check whether a value given for - * the -palette option is valid for a particular instance - * of a photo image. - * - * Results: - * A boolean value: 1 if the palette is acceptable, 0 otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -IsValidPalette(instancePtr, palette) - PhotoInstance *instancePtr; /* Instance to which the palette - * specification is to be applied. */ - char *palette; /* Palette specification string. */ -{ - int nRed, nGreen, nBlue, mono, numColors; - char *endp; - - /* - * First parse the specification: it must be of the form - * %d or %d/%d/%d. - */ - - nRed = strtol(palette, &endp, 10); - if ((endp == palette) || ((*endp != 0) && (*endp != '/')) - || (nRed < 2) || (nRed > 256)) { - return 0; - } - - if (*endp == 0) { - mono = 1; - nGreen = nBlue = nRed; - } else { - palette = endp + 1; - nGreen = strtol(palette, &endp, 10); - if ((endp == palette) || (*endp != '/') || (nGreen < 2) - || (nGreen > 256)) { - return 0; - } - palette = endp + 1; - nBlue = strtol(palette, &endp, 10); - if ((endp == palette) || (*endp != 0) || (nBlue < 2) - || (nBlue > 256)) { - return 0; - } - mono = 0; - } - - switch (instancePtr->visualInfo.class) { - case DirectColor: - case TrueColor: - if ((nRed > (1 << CountBits(instancePtr->visualInfo.red_mask))) - || (nGreen > (1 - << CountBits(instancePtr->visualInfo.green_mask))) - || (nBlue > (1 - << CountBits(instancePtr->visualInfo.blue_mask)))) { - return 0; - } - break; - case PseudoColor: - case StaticColor: - numColors = nRed; - if (!mono) { - numColors *= nGreen*nBlue; - } - if (numColors > (1 << instancePtr->visualInfo.depth)) { - return 0; - } - break; - case GrayScale: - case StaticGray: - if (!mono || (nRed > (1 << instancePtr->visualInfo.depth))) { - return 0; - } - break; - } - - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * CountBits -- - * - * This procedure counts how many bits are set to 1 in `mask'. - * - * Results: - * The integer number of bits. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -CountBits(mask) - pixel mask; /* Value to count the 1 bits in. */ -{ - int n; - - for( n = 0; mask != 0; mask &= mask - 1 ) - n++; - return n; -} - -/* - *---------------------------------------------------------------------- - * - * GetColorTable -- - * - * This procedure is called to allocate a table of colormap - * information for an instance of a photo image. Only one such - * table is allocated for all photo instances using the same - * display, colormap, palette and gamma values, so that the - * application need only request a set of colors from the X - * server once for all such photo widgets. This procedure - * maintains a hash table to find previously-allocated - * ColorTables. - * - * Results: - * None. - * - * Side effects: - * A new ColorTable may be allocated and placed in the hash - * table, and have colors allocated for it. - * - *---------------------------------------------------------------------- - */ - -static void -GetColorTable(instancePtr) - PhotoInstance *instancePtr; /* Instance needing a color table. */ -{ - ColorTable *colorPtr; - Tcl_HashEntry *entry; - ColorTableId id; - int isNew; - - /* - * Look for an existing ColorTable in the hash table. - */ - - memset((VOID *) &id, 0, sizeof(id)); - id.display = instancePtr->display; - id.colormap = instancePtr->colormap; - id.palette = instancePtr->palette; - id.gamma = instancePtr->gamma; - if (!imgPhotoColorHashInitialized) { - Tcl_InitHashTable(&imgPhotoColorHash, N_COLOR_HASH); - imgPhotoColorHashInitialized = 1; - } - entry = Tcl_CreateHashEntry(&imgPhotoColorHash, (char *) &id, &isNew); - - if (!isNew) { - /* - * Re-use the existing entry. - */ - - colorPtr = (ColorTable *) Tcl_GetHashValue(entry); - - } else { - /* - * No color table currently available; need to make one. - */ - - colorPtr = (ColorTable *) ckalloc(sizeof(ColorTable)); - - /* - * The following line of code should not normally be needed due - * to the assignment in the following line. However, it compensates - * for bugs in some compilers (HP, for example) where - * sizeof(ColorTable) is 24 but the assignment only copies 20 bytes, - * leaving 4 bytes uninitialized; these cause problems when using - * the id for lookups in imgPhotoColorHash, and can result in - * core dumps. - */ - - memset((VOID *) &colorPtr->id, 0, sizeof(ColorTableId)); - colorPtr->id = id; - Tk_PreserveColormap(colorPtr->id.display, colorPtr->id.colormap); - colorPtr->flags = 0; - colorPtr->refCount = 0; - colorPtr->liveRefCount = 0; - colorPtr->numColors = 0; - colorPtr->visualInfo = instancePtr->visualInfo; - colorPtr->pixelMap = NULL; - Tcl_SetHashValue(entry, colorPtr); - } - - colorPtr->refCount++; - colorPtr->liveRefCount++; - instancePtr->colorTablePtr = colorPtr; - if (colorPtr->flags & DISPOSE_PENDING) { - Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr); - colorPtr->flags &= ~DISPOSE_PENDING; - } - - /* - * Allocate colors for this color table if necessary. - */ - - if ((colorPtr->numColors == 0) - && ((colorPtr->flags & BLACK_AND_WHITE) == 0)) { - AllocateColors(colorPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * FreeColorTable -- - * - * This procedure is called when an instance ceases using a - * color table. - * - * Results: - * None. - * - * Side effects: - * If no other instances are using this color table, a when-idle - * handler is registered to free up the color table and the colors - * allocated for it. - * - *---------------------------------------------------------------------- - */ - -static void -FreeColorTable(colorPtr) - ColorTable *colorPtr; /* Pointer to the color table which is - * no longer required by an instance. */ -{ - colorPtr->refCount--; - if (colorPtr->refCount > 0) { - return; - } - if ((colorPtr->flags & DISPOSE_PENDING) == 0) { - Tcl_DoWhenIdle(DisposeColorTable, (ClientData) colorPtr); - colorPtr->flags |= DISPOSE_PENDING; - } -} - -/* - *---------------------------------------------------------------------- - * - * AllocateColors -- - * - * This procedure allocates the colors required by a color table, - * and sets up the fields in the color table data structure which - * are used in dithering. - * - * Results: - * None. - * - * Side effects: - * Colors are allocated from the X server. Fields in the - * color table data structure are updated. - * - *---------------------------------------------------------------------- - */ - -static void -AllocateColors(colorPtr) - ColorTable *colorPtr; /* Pointer to the color table requiring - * colors to be allocated. */ -{ - int i, r, g, b, rMult, mono; - int numColors, nRed, nGreen, nBlue; - double fr, fg, fb, igam; - XColor *colors; - unsigned long *pixels; - - /* 16-bit intensity value for i/n of full intensity. */ -# define CFRAC(i, n) ((i) * 65535 / (n)) - - /* As for CFRAC, but apply exponent of g. */ -# define CGFRAC(i, n, g) ((int)(65535 * pow((double)(i) / (n), (g)))) - - /* - * First parse the palette specification to get the required number of - * shades of each primary. - */ - - mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue) - <= 1; - igam = 1.0 / colorPtr->id.gamma; - - /* - * Each time around this loop, we reduce the number of colors we're - * trying to allocate until we succeed in allocating all of the colors - * we need. - */ - - for (;;) { - /* - * If we are using 1 bit/pixel, we don't need to allocate - * any colors (we just use the foreground and background - * colors in the GC). - */ - - if (mono && (nRed <= 2)) { - colorPtr->flags |= BLACK_AND_WHITE; - return; - } - - /* - * Calculate the RGB coordinates of the colors we want to - * allocate and store them in *colors. - */ - - if ((colorPtr->visualInfo.class == DirectColor) - || (colorPtr->visualInfo.class == TrueColor)) { - - /* - * Direct/True Color: allocate shades of red, green, blue - * independently. - */ - - if (mono) { - numColors = nGreen = nBlue = nRed; - } else { - numColors = MAX(MAX(nRed, nGreen), nBlue); - } - colors = (XColor *) ckalloc(numColors * sizeof(XColor)); - - for (i = 0; i < numColors; ++i) { - if (igam == 1.0) { - colors[i].red = CFRAC(i, nRed - 1); - colors[i].green = CFRAC(i, nGreen - 1); - colors[i].blue = CFRAC(i, nBlue - 1); - } else { - colors[i].red = CGFRAC(i, nRed - 1, igam); - colors[i].green = CGFRAC(i, nGreen - 1, igam); - colors[i].blue = CGFRAC(i, nBlue - 1, igam); - } - } - } else { - /* - * PseudoColor, StaticColor, GrayScale or StaticGray visual: - * we have to allocate each color in the color cube separately. - */ - - numColors = (mono) ? nRed: (nRed * nGreen * nBlue); - colors = (XColor *) ckalloc(numColors * sizeof(XColor)); - - if (!mono) { - /* - * Color display using a PseudoColor or StaticColor visual. - */ - - i = 0; - for (r = 0; r < nRed; ++r) { - for (g = 0; g < nGreen; ++g) { - for (b = 0; b < nBlue; ++b) { - if (igam == 1.0) { - colors[i].red = CFRAC(r, nRed - 1); - colors[i].green = CFRAC(g, nGreen - 1); - colors[i].blue = CFRAC(b, nBlue - 1); - } else { - colors[i].red = CGFRAC(r, nRed - 1, igam); - colors[i].green = CGFRAC(g, nGreen - 1, igam); - colors[i].blue = CGFRAC(b, nBlue - 1, igam); - } - i++; - } - } - } - } else { - /* - * Monochrome display - allocate the shades of grey we want. - */ - - for (i = 0; i < numColors; ++i) { - if (igam == 1.0) { - r = CFRAC(i, numColors - 1); - } else { - r = CGFRAC(i, numColors - 1, igam); - } - colors[i].red = colors[i].green = colors[i].blue = r; - } - } - } - - /* - * Now try to allocate the colors we've calculated. - */ - - pixels = (unsigned long *) ckalloc(numColors * sizeof(unsigned long)); - for (i = 0; i < numColors; ++i) { - if (!XAllocColor(colorPtr->id.display, colorPtr->id.colormap, - &colors[i])) { - - /* - * Can't get all the colors we want in the default colormap; - * first try freeing colors from other unused color tables. - */ - - if (!ReclaimColors(&colorPtr->id, numColors - i) - || !XAllocColor(colorPtr->id.display, - colorPtr->id.colormap, &colors[i])) { - /* - * Still can't allocate the color. - */ - break; - } - } - pixels[i] = colors[i].pixel; - } - - /* - * If we didn't get all of the colors, reduce the - * resolution of the color cube, free the ones we got, - * and try again. - */ - - if (i >= numColors) { - break; - } - XFreeColors(colorPtr->id.display, colorPtr->id.colormap, pixels, i, 0); - ckfree((char *) colors); - ckfree((char *) pixels); - - if (!mono) { - if ((nRed == 2) && (nGreen == 2) && (nBlue == 2)) { - /* - * Fall back to 1-bit monochrome display. - */ - - mono = 1; - } else { - /* - * Reduce the number of shades of each primary to about - * 3/4 of the previous value. This should reduce the - * total number of colors required to about half the - * previous value for PseudoColor displays. - */ - - nRed = (nRed * 3 + 2) / 4; - nGreen = (nGreen * 3 + 2) / 4; - nBlue = (nBlue * 3 + 2) / 4; - } - } else { - /* - * Reduce the number of shades of gray to about 1/2. - */ - - nRed = nRed / 2; - } - } - - /* - * We have allocated all of the necessary colors: - * fill in various fields of the ColorTable record. - */ - - if (!mono) { - colorPtr->flags |= COLOR_WINDOW; - - /* - * The following is a hairy hack. We only want to index into - * the pixelMap on colormap displays. However, if the display - * is on Windows, then we actually want to store the index not - * the value since we will be passing the color table into the - * TkPutImage call. - */ - -#ifndef __WIN32__ - if ((colorPtr->visualInfo.class != DirectColor) - && (colorPtr->visualInfo.class != TrueColor)) { - colorPtr->flags |= MAP_COLORS; - } -#endif /* __WIN32__ */ - } - - colorPtr->numColors = numColors; - colorPtr->pixelMap = pixels; - - /* - * Set up quantization tables for dithering. - */ - rMult = nGreen * nBlue; - for (i = 0; i < 256; ++i) { - r = (i * (nRed - 1) + 127) / 255; - if (mono) { - fr = (double) colors[r].red / 65535.0; - if (colorPtr->id.gamma != 1.0 ) { - fr = pow(fr, colorPtr->id.gamma); - } - colorPtr->colorQuant[0][i] = (int)(fr * 255.99); - colorPtr->redValues[i] = colors[r].pixel; - } else { - g = (i * (nGreen - 1) + 127) / 255; - b = (i * (nBlue - 1) + 127) / 255; - if ((colorPtr->visualInfo.class == DirectColor) - || (colorPtr->visualInfo.class == TrueColor)) { - colorPtr->redValues[i] = colors[r].pixel - & colorPtr->visualInfo.red_mask; - colorPtr->greenValues[i] = colors[g].pixel - & colorPtr->visualInfo.green_mask; - colorPtr->blueValues[i] = colors[b].pixel - & colorPtr->visualInfo.blue_mask; - } else { - r *= rMult; - g *= nBlue; - colorPtr->redValues[i] = r; - colorPtr->greenValues[i] = g; - colorPtr->blueValues[i] = b; - } - fr = (double) colors[r].red / 65535.0; - fg = (double) colors[g].green / 65535.0; - fb = (double) colors[b].blue / 65535.0; - if (colorPtr->id.gamma != 1.0) { - fr = pow(fr, colorPtr->id.gamma); - fg = pow(fg, colorPtr->id.gamma); - fb = pow(fb, colorPtr->id.gamma); - } - colorPtr->colorQuant[0][i] = (int)(fr * 255.99); - colorPtr->colorQuant[1][i] = (int)(fg * 255.99); - colorPtr->colorQuant[2][i] = (int)(fb * 255.99); - } - } - - ckfree((char *) colors); -} - -/* - *---------------------------------------------------------------------- - * - * DisposeColorTable -- - * - * - * Results: - * None. - * - * Side effects: - * The colors in the argument color table are freed, as is the - * color table structure itself. The color table is removed - * from the hash table which is used to locate color tables. - * - *---------------------------------------------------------------------- - */ - -static void -DisposeColorTable(clientData) - ClientData clientData; /* Pointer to the ColorTable whose - * colors are to be released. */ -{ - ColorTable *colorPtr; - Tcl_HashEntry *entry; - - colorPtr = (ColorTable *) clientData; - if (colorPtr->pixelMap != NULL) { - if (colorPtr->numColors > 0) { - XFreeColors(colorPtr->id.display, colorPtr->id.colormap, - colorPtr->pixelMap, colorPtr->numColors, 0); - Tk_FreeColormap(colorPtr->id.display, colorPtr->id.colormap); - } - ckfree((char *) colorPtr->pixelMap); - } - - entry = Tcl_FindHashEntry(&imgPhotoColorHash, (char *) &colorPtr->id); - if (entry == NULL) { - panic("DisposeColorTable couldn't find hash entry"); - } - Tcl_DeleteHashEntry(entry); - - ckfree((char *) colorPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ReclaimColors -- - * - * This procedure is called to try to free up colors in the - * colormap used by a color table. It looks for other color - * tables with the same colormap and with a zero live reference - * count, and frees their colors. It only does so if there is - * the possibility of freeing up at least `numColors' colors. - * - * Results: - * The return value is TRUE if any colors were freed, FALSE - * otherwise. - * - * Side effects: - * ColorTables which are not currently in use may lose their - * color allocations. - * - *---------------------------------------------------------------------- */ - -static int -ReclaimColors(id, numColors) - ColorTableId *id; /* Pointer to information identifying - * the color table which needs more colors. */ - int numColors; /* Number of colors required. */ -{ - Tcl_HashSearch srch; - Tcl_HashEntry *entry; - ColorTable *colorPtr; - int nAvail; - - /* - * First scan through the color hash table to get an - * upper bound on how many colors we might be able to free. - */ - - nAvail = 0; - entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch); - while (entry != NULL) { - colorPtr = (ColorTable *) Tcl_GetHashValue(entry); - if ((colorPtr->id.display == id->display) - && (colorPtr->id.colormap == id->colormap) - && (colorPtr->liveRefCount == 0 )&& (colorPtr->numColors != 0) - && ((colorPtr->id.palette != id->palette) - || (colorPtr->id.gamma != id->gamma))) { - - /* - * We could take this guy's colors off him. - */ - - nAvail += colorPtr->numColors; - } - entry = Tcl_NextHashEntry(&srch); - } - - /* - * nAvail is an (over)estimate of the number of colors we could free. - */ - - if (nAvail < numColors) { - return 0; - } - - /* - * Scan through a second time freeing colors. - */ - - entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch); - while ((entry != NULL) && (numColors > 0)) { - colorPtr = (ColorTable *) Tcl_GetHashValue(entry); - if ((colorPtr->id.display == id->display) - && (colorPtr->id.colormap == id->colormap) - && (colorPtr->liveRefCount == 0) && (colorPtr->numColors != 0) - && ((colorPtr->id.palette != id->palette) - || (colorPtr->id.gamma != id->gamma))) { - - /* - * Free the colors that this ColorTable has. - */ - - XFreeColors(colorPtr->id.display, colorPtr->id.colormap, - colorPtr->pixelMap, colorPtr->numColors, 0); - numColors -= colorPtr->numColors; - colorPtr->numColors = 0; - ckfree((char *) colorPtr->pixelMap); - colorPtr->pixelMap = NULL; - } - - entry = Tcl_NextHashEntry(&srch); - } - return 1; /* we freed some colors */ -} - -/* - *---------------------------------------------------------------------- - * - * DisposeInstance -- - * - * This procedure is called to finally free up an instance - * of a photo image which is no longer required. - * - * Results: - * None. - * - * Side effects: - * The instance data structure and the resources it references - * are freed. - * - *---------------------------------------------------------------------- - */ - -static void -DisposeInstance(clientData) - ClientData clientData; /* Pointer to the instance whose resources - * are to be released. */ -{ - PhotoInstance *instancePtr = (PhotoInstance *) clientData; - PhotoInstance *prevPtr; - - if (instancePtr->pixels != None) { - Tk_FreePixmap(instancePtr->display, instancePtr->pixels); - } - if (instancePtr->gc != None) { - Tk_FreeGC(instancePtr->display, instancePtr->gc); - } - if (instancePtr->imagePtr != NULL) { - XFree((char *) instancePtr->imagePtr); - } - if (instancePtr->error != NULL) { - ckfree((char *) instancePtr->error); - } - if (instancePtr->colorTablePtr != NULL) { - FreeColorTable(instancePtr->colorTablePtr); - } - - if (instancePtr->masterPtr->instancePtr == instancePtr) { - instancePtr->masterPtr->instancePtr = instancePtr->nextPtr; - } else { - for (prevPtr = instancePtr->masterPtr->instancePtr; - prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) { - /* Empty loop body */ - } - prevPtr->nextPtr = instancePtr->nextPtr; - } - Tk_FreeColormap(instancePtr->display, instancePtr->colormap); - ckfree((char *) instancePtr); -} - -/* - *---------------------------------------------------------------------- - * - * MatchFileFormat -- - * - * This procedure is called to find a photo image file format - * handler which can parse the image data in the given file. - * If a user-specified format string is provided, only handlers - * whose names match a prefix of the format string are tried. - * - * Results: - * A standard TCL return value. If the return value is TCL_OK, a - * pointer to the image format record is returned in - * *imageFormatPtr, and the width and height of the image are - * returned in *widthPtr and *heightPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, - widthPtr, heightPtr) - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ - Tk_PhotoImageFormat **imageFormatPtr; - /* A pointer to the photo image format - * record is returned here. */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here. */ -{ - int matched; - Tk_PhotoImageFormat *formatPtr; - - /* - * Scan through the table of file format handlers to find - * one which can handle the image. - */ - - matched = 0; - for (formatPtr = formatList; formatPtr != NULL; - formatPtr = formatPtr->nextPtr) { - if (formatString != NULL) { - if (strncasecmp(formatString, formatPtr->name, - strlen(formatPtr->name)) != 0) { - continue; - } - matched = 1; - if (formatPtr->fileMatchProc == NULL) { - Tcl_AppendResult(interp, "-file option isn't supported for ", - formatString, " images", (char *) NULL); - return TCL_ERROR; - } - } - if (formatPtr->fileMatchProc != NULL) { - (void) Tcl_Seek(chan, 0L, SEEK_SET); - - if ((*formatPtr->fileMatchProc)(chan, fileName, formatString, - widthPtr, heightPtr)) { - if (*widthPtr < 1) { - *widthPtr = 1; - } - if (*heightPtr < 1) { - *heightPtr = 1; - } - break; - } - } - } - - if (formatPtr == NULL) { - if ((formatString != NULL) && !matched) { - Tcl_AppendResult(interp, "image file format \"", formatString, - "\" is not supported", (char *) NULL); - } else { - Tcl_AppendResult(interp, - "couldn't recognize data in image file \"", - fileName, "\"", (char *) NULL); - } - return TCL_ERROR; - } - - *imageFormatPtr = formatPtr; - (void) Tcl_Seek(chan, 0L, SEEK_SET); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * MatchStringFormat -- - * - * This procedure is called to find a photo image file format - * handler which can parse the image data in the given string. - * If a user-specified format string is provided, only handlers - * whose names match a prefix of the format string are tried. - * - * Results: - * A standard TCL return value. If the return value is TCL_OK, a - * pointer to the image format record is returned in - * *imageFormatPtr, and the width and height of the image are - * returned in *widthPtr and *heightPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -MatchStringFormat(interp, string, formatString, imageFormatPtr, - widthPtr, heightPtr) - Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - char *string; /* String containing the image data. */ - char *formatString; /* User-specified format string, or NULL. */ - Tk_PhotoImageFormat **imageFormatPtr; - /* A pointer to the photo image format - * record is returned here. */ - int *widthPtr, *heightPtr; /* The dimensions of the image are - * returned here. */ -{ - int matched; - Tk_PhotoImageFormat *formatPtr; - - /* - * Scan through the table of file format handlers to find - * one which can handle the image. - */ - - matched = 0; - for (formatPtr = formatList; formatPtr != NULL; - formatPtr = formatPtr->nextPtr) { - if (formatString != NULL) { - if (strncasecmp(formatString, formatPtr->name, - strlen(formatPtr->name)) != 0) { - continue; - } - matched = 1; - if (formatPtr->stringMatchProc == NULL) { - Tcl_AppendResult(interp, "-data option isn't supported for ", - formatString, " images", (char *) NULL); - return TCL_ERROR; - } - } - if ((formatPtr->stringMatchProc != NULL) - && (*formatPtr->stringMatchProc)(string, formatString, - widthPtr, heightPtr)) { - break; - } - } - - if (formatPtr == NULL) { - if ((formatString != NULL) && !matched) { - Tcl_AppendResult(interp, "image format \"", formatString, - "\" is not supported", (char *) NULL); - } else { - Tcl_AppendResult(interp, "couldn't recognize image data", - (char *) NULL); - } - return TCL_ERROR; - } - - *imageFormatPtr = formatPtr; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FindPhoto -- - * - * This procedure is called to get an opaque handle (actually a - * PhotoMaster *) for a given image, which can be used in - * subsequent calls to Tk_PhotoPutBlock, etc. The `name' - * parameter is the name of the image. - * - * Results: - * The handle for the photo image, or NULL if there is no - * photo image with the name given. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_PhotoHandle -Tk_FindPhoto(interp, imageName) - Tcl_Interp *interp; /* Interpreter (application) in which image - * exists. */ - char *imageName; /* Name of the desired photo image. */ -{ - ClientData clientData; - Tk_ImageType *typePtr; - - clientData = Tk_GetImageMasterData(interp, imageName, &typePtr); - if (typePtr != &tkPhotoImageType) { - return NULL; - } - return (Tk_PhotoHandle) clientData; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoPutBlock -- - * - * This procedure is called to put image data into a photo image. - * - * Results: - * None. - * - * Side effects: - * The image data is stored. The image may be expanded. - * The Tk image code is informed that the image has changed. - * - *---------------------------------------------------------------------- */ - -void -Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) - Tk_PhotoHandle handle; /* Opaque handle for the photo image - * to be updated. */ - register Tk_PhotoImageBlock *blockPtr; - /* Pointer to a structure describing the - * pixel data to be copied into the image. */ - int x, y; /* Coordinates of the top-left pixel to - * be updated in the image. */ - int width, height; /* Dimensions of the area of the image - * to be updated. */ -{ - register PhotoMaster *masterPtr; - int xEnd, yEnd; - int greenOffset, blueOffset; - int wLeft, hLeft; - int wCopy, hCopy; - unsigned char *srcPtr, *srcLinePtr; - unsigned char *destPtr, *destLinePtr; - int pitch; - XRectangle rect; - - masterPtr = (PhotoMaster *) handle; - - if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) { - width = masterPtr->userWidth - x; - } - if ((masterPtr->userHeight != 0) - && ((y + height) > masterPtr->userHeight)) { - height = masterPtr->userHeight - y; - } - if ((width <= 0) || (height <= 0)) - return; - - xEnd = x + width; - yEnd = y + height; - if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) { - ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width), - MAX(yEnd, masterPtr->height)); - } - - if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY) - && (x < masterPtr->ditherX))) { - /* - * The dithering isn't correct past the start of this block. - */ - masterPtr->ditherX = x; - masterPtr->ditherY = y; - } - - /* - * If this image block could have different red, green and blue - * components, mark it as a color image. - */ - - greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; - blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - if ((greenOffset != 0) || (blueOffset != 0)) { - masterPtr->flags |= COLOR_IMAGE; - } - - /* - * Copy the data into our local 24-bit/pixel array. - * If we can do it with a single memcpy, we do. - */ - - destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 3; - pitch = masterPtr->width * 3; - - if ((blockPtr->pixelSize == 3) && (greenOffset == 1) && (blueOffset == 2) - && (width <= blockPtr->width) && (height <= blockPtr->height) - && ((height == 1) || ((x == 0) && (width == masterPtr->width) - && (blockPtr->pitch == pitch)))) { - memcpy((VOID *) destLinePtr, - (VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]), - (size_t) (height * width * 3)); - } else { - for (hLeft = height; hLeft > 0;) { - srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0]; - hCopy = MIN(hLeft, blockPtr->height); - hLeft -= hCopy; - for (; hCopy > 0; --hCopy) { - destPtr = destLinePtr; - for (wLeft = width; wLeft > 0;) { - wCopy = MIN(wLeft, blockPtr->width); - wLeft -= wCopy; - srcPtr = srcLinePtr; - for (; wCopy > 0; --wCopy) { - *destPtr++ = srcPtr[0]; - *destPtr++ = srcPtr[greenOffset]; - *destPtr++ = srcPtr[blueOffset]; - srcPtr += blockPtr->pixelSize; - } - } - srcLinePtr += blockPtr->pitch; - destLinePtr += pitch; - } - } - } - - /* - * Add this new block to the region which specifies which data is valid. - */ - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - TkUnionRectWithRegion(&rect, masterPtr->validRegion, - masterPtr->validRegion); - - /* - * Update each instance. - */ - - Dither(masterPtr, x, y, width, height); - - /* - * Tell the core image code that this image has changed. - */ - - Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width, - masterPtr->height); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoPutZoomedBlock -- - * - * This procedure is called to put image data into a photo image, - * with possible subsampling and/or zooming of the pixels. - * - * Results: - * None. - * - * Side effects: - * The image data is stored. The image may be expanded. - * The Tk image code is informed that the image has changed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, - subsampleX, subsampleY) - Tk_PhotoHandle handle; /* Opaque handle for the photo image - * to be updated. */ - register Tk_PhotoImageBlock *blockPtr; - /* Pointer to a structure describing the - * pixel data to be copied into the image. */ - int x, y; /* Coordinates of the top-left pixel to - * be updated in the image. */ - int width, height; /* Dimensions of the area of the image - * to be updated. */ - int zoomX, zoomY; /* Zoom factors for the X and Y axes. */ - int subsampleX, subsampleY; /* Subsampling factors for the X and Y axes. */ -{ - register PhotoMaster *masterPtr; - int xEnd, yEnd; - int greenOffset, blueOffset; - int wLeft, hLeft; - int wCopy, hCopy; - int blockWid, blockHt; - unsigned char *srcPtr, *srcLinePtr, *srcOrigPtr; - unsigned char *destPtr, *destLinePtr; - int pitch; - int xRepeat, yRepeat; - int blockXSkip, blockYSkip; - XRectangle rect; - - if ((zoomX == 1) && (zoomY == 1) && (subsampleX == 1) - && (subsampleY == 1)) { - Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height); - return; - } - - masterPtr = (PhotoMaster *) handle; - - if ((zoomX <= 0) || (zoomY <= 0)) - return; - if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) { - width = masterPtr->userWidth - x; - } - if ((masterPtr->userHeight != 0) - && ((y + height) > masterPtr->userHeight)) { - height = masterPtr->userHeight - y; - } - if ((width <= 0) || (height <= 0)) - return; - - xEnd = x + width; - yEnd = y + height; - if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) { - int sameSrc = (blockPtr->pixelPtr == masterPtr->pix24); - ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width), - MAX(yEnd, masterPtr->height)); - if (sameSrc) { - blockPtr->pixelPtr = masterPtr->pix24; - } - } - - if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY) - && (x < masterPtr->ditherX))) { - /* - * The dithering isn't correct past the start of this block. - */ - - masterPtr->ditherX = x; - masterPtr->ditherY = y; - } - - /* - * If this image block could have different red, green and blue - * components, mark it as a color image. - */ - - greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; - blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - if ((greenOffset != 0) || (blueOffset != 0)) { - masterPtr->flags |= COLOR_IMAGE; - } - - /* - * Work out what area the pixel data in the block expands to after - * subsampling and zooming. - */ - - blockXSkip = subsampleX * blockPtr->pixelSize; - blockYSkip = subsampleY * blockPtr->pitch; - if (subsampleX > 0) - blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX; - else if (subsampleX == 0) - blockWid = width; - else - blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX; - if (subsampleY > 0) - blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY; - else if (subsampleY == 0) - blockHt = height; - else - blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY; - - /* - * Copy the data into our local 24-bit/pixel array. - */ - - destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 3; - srcOrigPtr = blockPtr->pixelPtr + blockPtr->offset[0]; - if (subsampleX < 0) { - srcOrigPtr += (blockPtr->width - 1) * blockPtr->pixelSize; - } - if (subsampleY < 0) { - srcOrigPtr += (blockPtr->height - 1) * blockPtr->pitch; - } - - pitch = masterPtr->width * 3; - for (hLeft = height; hLeft > 0; ) { - hCopy = MIN(hLeft, blockHt); - hLeft -= hCopy; - yRepeat = zoomY; - srcLinePtr = srcOrigPtr; - for (; hCopy > 0; --hCopy) { - destPtr = destLinePtr; - for (wLeft = width; wLeft > 0;) { - wCopy = MIN(wLeft, blockWid); - wLeft -= wCopy; - srcPtr = srcLinePtr; - for (; wCopy > 0; wCopy -= zoomX) { - for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) { - *destPtr++ = srcPtr[0]; - *destPtr++ = srcPtr[greenOffset]; - *destPtr++ = srcPtr[blueOffset]; - } - srcPtr += blockXSkip; - } - } - destLinePtr += pitch; - yRepeat--; - if (yRepeat <= 0) { - srcLinePtr += blockYSkip; - yRepeat = zoomY; - } - } - } - - /* - * Add this new block to the region that specifies which data is valid. - */ - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - TkUnionRectWithRegion(&rect, masterPtr->validRegion, - masterPtr->validRegion); - - /* - * Update each instance. - */ - - Dither(masterPtr, x, y, width, height); - - /* - * Tell the core image code that this image has changed. - */ - - Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width, - masterPtr->height); -} - -/* - *---------------------------------------------------------------------- - * - * Dither -- - * - * This procedure is called to update an area of each instance's - * pixmap by dithering the corresponding area of the image master. - * - * Results: - * None. - * - * Side effects: - * The pixmap of each instance of this image gets updated. - * The fields in *masterPtr indicating which area of the image - * is correctly dithered get updated. - * - *---------------------------------------------------------------------- - */ - -static void -Dither(masterPtr, x, y, width, height) - PhotoMaster *masterPtr; /* Image master whose instances are - * to be updated. */ - int x, y; /* Coordinates of the top-left pixel - * in the area to be dithered. */ - int width, height; /* Dimensions of the area to be dithered. */ -{ - PhotoInstance *instancePtr; - - if ((width <= 0) || (height <= 0)) { - return; - } - - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - DitherInstance(instancePtr, x, y, width, height); - } - - /* - * Work out whether this block will be correctly dithered - * and whether it will extend the correctly dithered region. - */ - - if (((y < masterPtr->ditherY) - || ((y == masterPtr->ditherY) && (x <= masterPtr->ditherX))) - && ((y + height) > (masterPtr->ditherY))) { - - /* - * This block starts inside (or immediately after) the correctly - * dithered region, so the first scan line at least will be right. - * Furthermore this block extends into scanline masterPtr->ditherY. - */ - - if ((x == 0) && (width == masterPtr->width)) { - /* - * We are doing the full width, therefore the dithering - * will be correct to the end. - */ - - masterPtr->ditherX = 0; - masterPtr->ditherY = y + height; - } else { - /* - * We are doing partial scanlines, therefore the - * correctly-dithered region will be extended by - * at most one scan line. - */ - - if (x <= masterPtr->ditherX) { - masterPtr->ditherX = x + width; - if (masterPtr->ditherX >= masterPtr->width) { - masterPtr->ditherX = 0; - masterPtr->ditherY++; - } - } - } - } - -} - -/* - *---------------------------------------------------------------------- - * - * DitherInstance -- - * - * This procedure is called to update an area of an instance's - * pixmap by dithering the corresponding area of the master. - * - * Results: - * None. - * - * Side effects: - * The instance's pixmap gets updated. - * - *---------------------------------------------------------------------- - */ - -static void -DitherInstance(instancePtr, xStart, yStart, width, height) - PhotoInstance *instancePtr; /* The instance to be updated. */ - int xStart, yStart; /* Coordinates of the top-left pixel in the - * block to be dithered. */ - int width, height; /* Dimensions of the block to be dithered. */ -{ - PhotoMaster *masterPtr; - ColorTable *colorPtr; - XImage *imagePtr; - int nLines, bigEndian; - int i, c, x, y; - int xEnd, yEnd; - int bitsPerPixel, bytesPerLine, lineLength; - unsigned char *srcLinePtr, *srcPtr; - schar *errLinePtr, *errPtr; - unsigned char *destBytePtr, *dstLinePtr; - pixel *destLongPtr; - pixel firstBit, word, mask; - int col[3]; - int doDithering = 1; - - colorPtr = instancePtr->colorTablePtr; - masterPtr = instancePtr->masterPtr; - - /* - * Turn dithering off in certain cases where it is not - * needed (TrueColor, DirectColor with many colors). - */ - - if ((colorPtr->visualInfo.class == DirectColor) - || (colorPtr->visualInfo.class == TrueColor)) { - int nRed, nGreen, nBlue, result; - - result = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, - &nGreen, &nBlue); - if ((nRed >= 256) - && ((result == 1) || ((nGreen >= 256) && (nBlue >= 256)))) { - doDithering = 0; - } - } - - /* - * First work out how many lines to do at a time, - * then how many bytes we'll need for pixel storage, - * and allocate it. - */ - - nLines = (MAX_PIXELS + width - 1) / width; - if (nLines < 1) { - nLines = 1; - } - if (nLines > height ) { - nLines = height; - } - - imagePtr = instancePtr->imagePtr; - if (imagePtr == NULL) { - return; /* we must be really tight on memory */ - } - bitsPerPixel = imagePtr->bits_per_pixel; - bytesPerLine = ((bitsPerPixel * width + 31) >> 3) & ~3; - imagePtr->width = width; - imagePtr->height = nLines; - imagePtr->bytes_per_line = bytesPerLine; - imagePtr->data = (char *) ckalloc((unsigned) (imagePtr->bytes_per_line * nLines)); - bigEndian = imagePtr->bitmap_bit_order == MSBFirst; - firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1; - - lineLength = masterPtr->width * 3; - srcLinePtr = masterPtr->pix24 + yStart * lineLength + xStart * 3; - errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3; - xEnd = xStart + width; - - /* - * Loop over the image, doing at most nLines lines before - * updating the screen image. - */ - - for (; height > 0; height -= nLines) { - if (nLines > height) { - nLines = height; - } - dstLinePtr = (unsigned char *) imagePtr->data; - yEnd = yStart + nLines; - for (y = yStart; y < yEnd; ++y) { - srcPtr = srcLinePtr; - errPtr = errLinePtr; - destBytePtr = dstLinePtr; - destLongPtr = (pixel *) dstLinePtr; - if (colorPtr->flags & COLOR_WINDOW) { - /* - * Color window. We dither the three components - * independently, using Floyd-Steinberg dithering, - * which propagates errors from the quantization of - * pixels to the pixels below and to the right. - */ - - for (x = xStart; x < xEnd; ++x) { - if (doDithering) { - for (i = 0; i < 3; ++i) { - /* - * Compute the error propagated into this pixel - * for this component. - * If e[x,y] is the array of quantization error - * values, we compute - * 7/16 * e[x-1,y] + 1/16 * e[x-1,y-1] - * + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1] - * and round it to an integer. - * - * The expression ((c + 2056) >> 4) - 128 - * computes round(c / 16), and works correctly on - * machines without a sign-extending right shift. - */ - - c = (x > 0) ? errPtr[-3] * 7: 0; - if (y > 0) { - if (x > 0) { - c += errPtr[-lineLength-3]; - } - c += errPtr[-lineLength] * 5; - if ((x + 1) < masterPtr->width) { - c += errPtr[-lineLength+3] * 3; - } - } - - /* - * Add the propagated error to the value of this - * component, quantize it, and store the - * quantization error. - */ - - c = ((c + 2056) >> 4) - 128 + *srcPtr++; - if (c < 0) { - c = 0; - } else if (c > 255) { - c = 255; - } - col[i] = colorPtr->colorQuant[i][c]; - *errPtr++ = c - col[i]; - } - } else { - /* - * Output is virtually continuous in this case, - * so don't bother dithering. - */ - - col[0] = *srcPtr++; - col[1] = *srcPtr++; - col[2] = *srcPtr++; - } - - /* - * Translate the quantized component values into - * an X pixel value, and store it in the image. - */ - - i = colorPtr->redValues[col[0]] - + colorPtr->greenValues[col[1]] - + colorPtr->blueValues[col[2]]; - if (colorPtr->flags & MAP_COLORS) { - i = colorPtr->pixelMap[i]; - } - switch (bitsPerPixel) { - case NBBY: - *destBytePtr++ = i; - break; -#ifndef __WIN32__ -/* - * This case is not valid for Windows because the image format is different - * from the pixel format in Win32. Eventually we need to fix the image - * code in Tk to use the Windows native image ordering. This would speed - * up the image code for all of the common sizes. - */ - - case NBBY * sizeof(pixel): - *destLongPtr++ = i; - break; -#endif - default: - XPutPixel(imagePtr, x - xStart, y - yStart, - (unsigned) i); - } - } - - } else if (bitsPerPixel > 1) { - /* - * Multibit monochrome window. The operation here is similar - * to the color window case above, except that there is only - * one component. If the master image is in color, use the - * luminance computed as - * 0.344 * red + 0.5 * green + 0.156 * blue. - */ - - for (x = xStart; x < xEnd; ++x) { - c = (x > 0) ? errPtr[-1] * 7: 0; - if (y > 0) { - if (x > 0) { - c += errPtr[-lineLength-1]; - } - c += errPtr[-lineLength] * 5; - if (x + 1 < masterPtr->width) { - c += errPtr[-lineLength+1] * 3; - } - } - c = ((c + 2056) >> 4) - 128; - - if ((masterPtr->flags & COLOR_IMAGE) == 0) { - c += srcPtr[0]; - } else { - c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16 - + srcPtr[2] * 5 + 16) >> 5; - } - srcPtr += 3; - - if (c < 0) { - c = 0; - } else if (c > 255) { - c = 255; - } - i = colorPtr->colorQuant[0][c]; - *errPtr++ = c - i; - i = colorPtr->redValues[i]; - switch (bitsPerPixel) { - case NBBY: - *destBytePtr++ = i; - break; -#ifndef __WIN32__ -/* - * This case is not valid for Windows because the image format is different - * from the pixel format in Win32. Eventually we need to fix the image - * code in Tk to use the Windows native image ordering. This would speed - * up the image code for all of the common sizes. - */ - - case NBBY * sizeof(pixel): - *destLongPtr++ = i; - break; -#endif - default: - XPutPixel(imagePtr, x - xStart, y - yStart, - (unsigned) i); - } - } - } else { - /* - * 1-bit monochrome window. This is similar to the - * multibit monochrome case above, except that the - * quantization is simpler (we only have black = 0 - * and white = 255), and we produce an XY-Bitmap. - */ - - word = 0; - mask = firstBit; - for (x = xStart; x < xEnd; ++x) { - /* - * If we have accumulated a whole word, store it - * in the image and start a new word. - */ - - if (mask == 0) { - *destLongPtr++ = word; - mask = firstBit; - word = 0; - } - - c = (x > 0) ? errPtr[-1] * 7: 0; - if (y > 0) { - if (x > 0) { - c += errPtr[-lineLength-1]; - } - c += errPtr[-lineLength] * 5; - if (x + 1 < masterPtr->width) { - c += errPtr[-lineLength+1] * 3; - } - } - c = ((c + 2056) >> 4) - 128; - - if ((masterPtr->flags & COLOR_IMAGE) == 0) { - c += srcPtr[0]; - } else { - c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16 - + srcPtr[2] * 5 + 16) >> 5; - } - srcPtr += 3; - - if (c < 0) { - c = 0; - } else if (c > 255) { - c = 255; - } - if (c >= 128) { - word |= mask; - *errPtr++ = c - 255; - } else { - *errPtr++ = c; - } - mask = bigEndian? (mask >> 1): (mask << 1); - } - *destLongPtr = word; - } - srcLinePtr += lineLength; - errLinePtr += lineLength; - dstLinePtr += bytesPerLine; - } - - /* - * Update the pixmap for this instance with the block of - * pixels that we have just computed. - */ - - TkPutImage(colorPtr->pixelMap, colorPtr->numColors, - instancePtr->display, instancePtr->pixels, - instancePtr->gc, imagePtr, 0, 0, xStart, yStart, - (unsigned) width, (unsigned) nLines); - yStart = yEnd; - - } - - ckfree(imagePtr->data); - imagePtr->data = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoBlank -- - * - * This procedure is called to clear an entire photo image. - * - * Results: - * None. - * - * Side effects: - * The valid region for the image is set to the null region. - * The generic image code is notified that the image has changed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PhotoBlank(handle) - Tk_PhotoHandle handle; /* Handle for the image to be blanked. */ -{ - PhotoMaster *masterPtr; - PhotoInstance *instancePtr; - - masterPtr = (PhotoMaster *) handle; - masterPtr->ditherX = masterPtr->ditherY = 0; - masterPtr->flags = 0; - - /* - * The image has valid data nowhere. - */ - - if (masterPtr->validRegion != NULL) { - TkDestroyRegion(masterPtr->validRegion); - } - masterPtr->validRegion = TkCreateRegion(); - - /* - * Clear out the 24-bit pixel storage array. - * Clear out the dithering error arrays for each instance. - */ - - memset((VOID *) masterPtr->pix24, 0, - (size_t) (masterPtr->width * masterPtr->height * 3)); - for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; - instancePtr = instancePtr->nextPtr) { - if (instancePtr->error) { - memset((VOID *) instancePtr->error, 0, - (size_t) (masterPtr->width * masterPtr->height - * 3 * sizeof(schar))); - } - } - - /* - * Tell the core image code that this image has changed. - */ - - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width, - masterPtr->height, masterPtr->width, masterPtr->height); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoExpand -- - * - * This procedure is called to request that a photo image be - * expanded if necessary to be at least `width' pixels wide and - * `height' pixels high. If the user has declared a definite - * image size (using the -width and -height configuration - * options) then this call has no effect. - * - * Results: - * None. - * - * Side effects: - * The size of the photo image may change; if so the generic - * image code is informed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PhotoExpand(handle, width, height) - Tk_PhotoHandle handle; /* Handle for the image to be expanded. */ - int width, height; /* Desired minimum dimensions of the image. */ -{ - PhotoMaster *masterPtr; - - masterPtr = (PhotoMaster *) handle; - - if (width <= masterPtr->width) { - width = masterPtr->width; - } - if (height <= masterPtr->height) { - height = masterPtr->height; - } - if ((width != masterPtr->width) || (height != masterPtr->height)) { - ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width), - MAX(height, masterPtr->height)); - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width, - masterPtr->height); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoGetSize -- - * - * This procedure is called to obtain the current size of a photo - * image. - * - * Results: - * The image's width and height are returned in *widthp - * and *heightp. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PhotoGetSize(handle, widthPtr, heightPtr) - Tk_PhotoHandle handle; /* Handle for the image whose dimensions - * are requested. */ - int *widthPtr, *heightPtr; /* The dimensions of the image are returned - * here. */ -{ - PhotoMaster *masterPtr; - - masterPtr = (PhotoMaster *) handle; - *widthPtr = masterPtr->width; - *heightPtr = masterPtr->height; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoSetSize -- - * - * This procedure is called to set size of a photo image. - * This call is equivalent to using the -width and -height - * configuration options. - * - * Results: - * None. - * - * Side effects: - * The size of the image may change; if so the generic - * image code is informed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PhotoSetSize(handle, width, height) - Tk_PhotoHandle handle; /* Handle for the image whose size is to - * be set. */ - int width, height; /* New dimensions for the image. */ -{ - PhotoMaster *masterPtr; - - masterPtr = (PhotoMaster *) handle; - - masterPtr->userWidth = width; - masterPtr->userHeight = height; - ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width), - ((height > 0) ? height: masterPtr->height)); - Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, - masterPtr->width, masterPtr->height); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PhotoGetImage -- - * - * This procedure is called to obtain image data from a photo - * image. This procedure fills in the Tk_PhotoImageBlock structure - * pointed to by `blockPtr' with details of the address and - * layout of the image data in memory. - * - * Results: - * TRUE (1) indicating that image data is available, - * for backwards compatibility with the old photo widget. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_PhotoGetImage(handle, blockPtr) - Tk_PhotoHandle handle; /* Handle for the photo image from which - * image data is desired. */ - Tk_PhotoImageBlock *blockPtr; - /* Information about the address and layout - * of the image data is returned here. */ -{ - PhotoMaster *masterPtr; - - masterPtr = (PhotoMaster *) handle; - blockPtr->pixelPtr = masterPtr->pix24; - blockPtr->width = masterPtr->width; - blockPtr->height = masterPtr->height; - blockPtr->pitch = masterPtr->width * 3; - blockPtr->pixelSize = 3; - blockPtr->offset[0] = 0; - blockPtr->offset[1] = 1; - blockPtr->offset[2] = 2; - return 1; -} diff --git a/generic/tkImgUtil.c b/generic/tkImgUtil.c deleted file mode 100644 index 00c8b7d..0000000 --- a/generic/tkImgUtil.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * tkImgUtil.c -- - * - * This file contains image related utility functions. - * - * Copyright (c) 1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkImgUtil.c,v 1.2 1998/09/14 18:23:13 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" -#include "xbytes.h" - - -/* - *---------------------------------------------------------------------- - * - * TkAlignImageData -- - * - * This function takes an image and copies the data into an - * aligned buffer, performing any necessary bit swapping. - * - * Results: - * Returns a newly allocated buffer that should be freed by the - * caller. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -TkAlignImageData(image, alignment, bitOrder) - XImage *image; /* Image to be aligned. */ - int alignment; /* Number of bytes to which the data should - * be aligned (e.g. 2 or 4) */ - int bitOrder; /* Desired bit order: LSBFirst or MSBFirst. */ -{ - long dataWidth; - char *data, *srcPtr, *destPtr; - int i, j; - - if (image->bits_per_pixel != 1) { - panic("TkAlignImageData: Can't handle image depths greater than 1."); - } - - /* - * Compute line width for output data buffer. - */ - - dataWidth = image->bytes_per_line; - if (dataWidth % alignment) { - dataWidth += (alignment - (dataWidth % alignment)); - } - - data = ckalloc(dataWidth * image->height); - - destPtr = data; - for (i = 0; i < image->height; i++) { - srcPtr = &image->data[i * image->bytes_per_line]; - for (j = 0; j < dataWidth; j++) { - if (j >= image->bytes_per_line) { - *destPtr = 0; - } else if (image->bitmap_bit_order != bitOrder) { - *destPtr = xBitReverseTable[(unsigned char)(*(srcPtr++))]; - } else { - *destPtr = *(srcPtr++); - } - destPtr++; - } - } - return data; -} diff --git a/generic/tkInitScript.h b/generic/tkInitScript.h deleted file mode 100644 index a478fd0..0000000 --- a/generic/tkInitScript.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * tkInitScript.h -- - * - * This file contains Unix & Windows common init script - * It is not used on the Mac. (the mac init script is in tkMacInit.c) - * - * Copyright (c) 1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkInitScript.h,v 1.7 1998/09/14 18:23:13 stanton Exp $ - */ - -/* - * In order to find tk.tcl during initialization, the following script - * is invoked by Tk_Init(). It looks in several different directories: - * - * $tk_library - can specify a primary location, if set - * no other locations will be checked - * - * $env(TK_LIBRARY) - highest priority so user can always override - * the search path unless the application has - * specified an exact directory above - * - * $tcl_library/../tk$tk_version - * - look relative to init.tcl in an installed - * lib directory (e.g. /usr/local) - * - * <executable directory>/../lib/tk$tk_version - * - look for a lib/tk<ver> in a sibling of - * the bin directory (e.g. /usr/local) - * - * <executable directory>/../library - * - look in Tk build directory - * - * <executable directory>/../../tk$tk_patchLevel/library - * - look for Tk build directory relative - * to a parallel build directory - * - * The first directory on this path that contains a valid tk.tcl script - * will be set ast the value of tk_library. - * - * Note that this entire search mechanism can be bypassed by defining an - * alternate tkInit procedure before calling Tk_Init(). - */ - -static char initScript[] = "if {[info proc tkInit]==\"\"} {\n\ - proc tkInit {} {\n\ - global tk_library tk_version tk_patchLevel\n\ - rename tkInit {}\n\ - tcl_findLibrary tk $tk_version $tk_patchLevel tk.tcl TK_LIBRARY tk_library\n\ - }\n\ -}\n\ -tkInit"; - diff --git a/generic/tkInt.h b/generic/tkInt.h deleted file mode 100644 index d07155f..0000000 --- a/generic/tkInt.h +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * tkInt.h -- - * - * Declarations for things used internally by the Tk - * procedures but not exported outside the module. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: $Id: tkInt.h,v 1.7 1998/09/14 18:23:13 stanton Exp $ - */ - -#ifndef _TKINT -#define _TKINT - -#ifndef _TK -#include "tk.h" -#endif -#ifndef _TCL -#include "tcl.h" -#endif -#ifndef _TKPORT -#include <tkPort.h> -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * Opaque type declarations: - */ - -typedef struct TkColormap TkColormap; -typedef struct TkGrabEvent TkGrabEvent; -typedef struct Tk_PostscriptInfo Tk_PostscriptInfo; -typedef struct TkpCursor_ *TkpCursor; -typedef struct TkRegion_ *TkRegion; -typedef struct TkStressedCmap TkStressedCmap; -typedef struct TkBindInfo_ *TkBindInfo; - -/* - * Procedure types. - */ - -typedef int (TkBindEvalProc) _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, XEvent *eventPtr, Tk_Window tkwin, - KeySym keySym)); -typedef void (TkBindFreeProc) _ANSI_ARGS_((ClientData clientData)); -typedef Window (TkClassCreateProc) _ANSI_ARGS_((Tk_Window tkwin, - Window parent, ClientData instanceData)); -typedef void (TkClassGeometryProc) _ANSI_ARGS_((ClientData instanceData)); -typedef void (TkClassModalProc) _ANSI_ARGS_((Tk_Window tkwin, - XEvent *eventPtr)); - - -/* - * Widget class procedures used to implement platform specific widget - * behavior. - */ - -typedef struct TkClassProcs { - TkClassCreateProc *createProc; - /* Procedure to invoke when the - platform-dependent window needs to be - created. */ - TkClassGeometryProc *geometryProc; - /* Procedure to invoke when the geometry of a - window needs to be recalculated as a result - of some change in the system. */ - TkClassModalProc *modalProc; - /* Procedure to invoke after all bindings on a - widget have been triggered in order to - handle a modal loop. */ -} TkClassProcs; - -/* - * One of the following structures is maintained for each cursor in - * use in the system. This structure is used by tkCursor.c and the - * various system specific cursor files. - */ - -typedef struct TkCursor { - Tk_Cursor cursor; /* System specific identifier for cursor. */ - int refCount; /* Number of active uses of cursor. */ - Tcl_HashTable *otherTable; /* Second table (other than idTable) used - * to index this entry. */ - Tcl_HashEntry *hashPtr; /* Entry in otherTable for this structure - * (needed when deleting). */ -} TkCursor; - -/* - * One of the following structures is maintained for each display - * containing a window managed by Tk: - */ - -typedef struct TkDisplay { - Display *display; /* Xlib's info about display. */ - struct TkDisplay *nextPtr; /* Next in list of all displays. */ - char *name; /* Name of display (with any screen - * identifier removed). Malloc-ed. */ - Time lastEventTime; /* Time of last event received for this - * display. */ - - /* - * Information used primarily by tkBind.c: - */ - - int bindInfoStale; /* Non-zero means the variables in this - * part of the structure are potentially - * incorrect and should be recomputed. */ - unsigned int modeModMask; /* Has one bit set to indicate the modifier - * corresponding to "mode shift". If no - * such modifier, than this is zero. */ - unsigned int metaModMask; /* Has one bit set to indicate the modifier - * corresponding to the "Meta" key. If no - * such modifier, then this is zero. */ - unsigned int altModMask; /* Has one bit set to indicate the modifier - * corresponding to the "Meta" key. If no - * such modifier, then this is zero. */ - enum {LU_IGNORE, LU_CAPS, LU_SHIFT} lockUsage; - /* Indicates how to interpret lock modifier. */ - int numModKeyCodes; /* Number of entries in modKeyCodes array - * below. */ - KeyCode *modKeyCodes; /* Pointer to an array giving keycodes for - * all of the keys that have modifiers - * associated with them. Malloc'ed, but - * may be NULL. */ - - /* - * Information used by tkError.c only: - */ - - struct TkErrorHandler *errorPtr; - /* First in list of error handlers - * for this display. NULL means - * no handlers exist at present. */ - int deleteCount; /* Counts # of handlers deleted since - * last time inactive handlers were - * garbage-collected. When this number - * gets big, handlers get cleaned up. */ - - /* - * Information used by tkSend.c only: - */ - - Tk_Window commTkwin; /* Window used for communication - * between interpreters during "send" - * commands. NULL means send info hasn't - * been initialized yet. */ - Atom commProperty; /* X's name for comm property. */ - Atom registryProperty; /* X's name for property containing - * registry of interpreter names. */ - Atom appNameProperty; /* X's name for property used to hold the - * application name on each comm window. */ - - /* - * Information used by tkSelect.c and tkClipboard.c only: - */ - - struct TkSelectionInfo *selectionInfoPtr; - /* First in list of selection information - * records. Each entry contains information - * about the current owner of a particular - * selection on this display. */ - Atom multipleAtom; /* Atom for MULTIPLE. None means - * selection stuff isn't initialized. */ - Atom incrAtom; /* Atom for INCR. */ - Atom targetsAtom; /* Atom for TARGETS. */ - Atom timestampAtom; /* Atom for TIMESTAMP. */ - Atom textAtom; /* Atom for TEXT. */ - Atom compoundTextAtom; /* Atom for COMPOUND_TEXT. */ - Atom applicationAtom; /* Atom for TK_APPLICATION. */ - Atom windowAtom; /* Atom for TK_WINDOW. */ - Atom clipboardAtom; /* Atom for CLIPBOARD. */ - - Tk_Window clipWindow; /* Window used for clipboard ownership and to - * retrieve selections between processes. NULL - * means clipboard info hasn't been - * initialized. */ - int clipboardActive; /* 1 means we currently own the clipboard - * selection, 0 means we don't. */ - struct TkMainInfo *clipboardAppPtr; - /* Last application that owned clipboard. */ - struct TkClipboardTarget *clipTargetPtr; - /* First in list of clipboard type information - * records. Each entry contains information - * about the buffers for a given selection - * target. */ - - /* - * Information used by tkAtom.c only: - */ - - int atomInit; /* 0 means stuff below hasn't been - * initialized yet. */ - Tcl_HashTable nameTable; /* Maps from names to Atom's. */ - Tcl_HashTable atomTable; /* Maps from Atom's back to names. */ - - /* - * Information used by tkCursor.c only: - */ - - Font cursorFont; /* Font to use for standard cursors. - * None means font not loaded yet. */ - - /* - * Information used by tkGrab.c only: - */ - - struct TkWindow *grabWinPtr; - /* Window in which the pointer is currently - * grabbed, or NULL if none. */ - struct TkWindow *eventualGrabWinPtr; - /* Value that grabWinPtr will have once the - * grab event queue (below) has been - * completely emptied. */ - struct TkWindow *buttonWinPtr; - /* Window in which first mouse button was - * pressed while grab was in effect, or NULL - * if no such press in effect. */ - struct TkWindow *serverWinPtr; - /* If no application contains the pointer then - * this is NULL. Otherwise it contains the - * last window for which we've gotten an - * Enter or Leave event from the server (i.e. - * the last window known to have contained - * the pointer). Doesn't reflect events - * that were synthesized in tkGrab.c. */ - TkGrabEvent *firstGrabEventPtr; - /* First in list of enter/leave events - * synthesized by grab code. These events - * must be processed in order before any other - * events are processed. NULL means no such - * events. */ - TkGrabEvent *lastGrabEventPtr; - /* Last in list of synthesized events, or NULL - * if list is empty. */ - int grabFlags; /* Miscellaneous flag values. See definitions - * in tkGrab.c. */ - - /* - * Information used by tkXId.c only: - */ - - struct TkIdStack *idStackPtr; - /* First in list of chunks of free resource - * identifiers, or NULL if there are no free - * resources. */ - XID (*defaultAllocProc) _ANSI_ARGS_((Display *display)); - /* Default resource allocator for display. */ - struct TkIdStack *windowStackPtr; - /* First in list of chunks of window - * identifers that can't be reused right - * now. */ - int idCleanupScheduled; /* 1 means a call to WindowIdCleanup has - * already been scheduled, 0 means it - * hasn't. */ - - /* - * Information maintained by tkWindow.c for use later on by tkXId.c: - */ - - - int destroyCount; /* Number of Tk_DestroyWindow operations - * in progress. */ - unsigned long lastDestroyRequest; - /* Id of most recent XDestroyWindow request; - * can re-use ids in windowStackPtr when - * server has seen this request and event - * queue is empty. */ - - /* - * Information used by tkVisual.c only: - */ - - TkColormap *cmapPtr; /* First in list of all non-default colormaps - * allocated for this display. */ - - /* - * Information used by tkFocus.c only: - */ - - struct TkWindow *implicitWinPtr; - /* If the focus arrived at a toplevel window - * implicitly via an Enter event (rather - * than via a FocusIn event), this points - * to the toplevel window. Otherwise it is - * NULL. */ - struct TkWindow *focusPtr; /* Points to the window on this display that - * should be receiving keyboard events. When - * multiple applications on the display have - * the focus, this will refer to the - * innermost window in the innermost - * application. This information isn't used - * under Unix or Windows, but it's needed on - * the Macintosh. */ - - /* - * Used by tkColor.c only: - */ - - TkStressedCmap *stressPtr; /* First in list of colormaps that have - * filled up, so we have to pick an - * approximate color. */ - - /* - * Used by tkEvent.c only: - */ - - struct TkWindowEvent *delayedMotionPtr; - /* Points to a malloc-ed motion event - * whose processing has been delayed in - * the hopes that another motion event - * will come along right away and we can - * merge the two of them together. NULL - * means that there is no delayed motion - * event. */ - - /* - * Miscellaneous information: - */ - -#ifdef TK_USE_INPUT_METHODS - XIM inputMethod; /* Input method for this display */ -#endif /* TK_USE_INPUT_METHODS */ - Tcl_HashTable winTable; /* Maps from X window ids to TkWindow ptrs. */ - - int refCount; /* Reference count of how many Tk applications - * are using this display. Used to clean up - * the display when we no longer have any - * Tk applications using it. - */ -} TkDisplay; - -/* - * One of the following structures exists for each error handler - * created by a call to Tk_CreateErrorHandler. The structure - * is managed by tkError.c. - */ - -typedef struct TkErrorHandler { - TkDisplay *dispPtr; /* Display to which handler applies. */ - unsigned long firstRequest; /* Only errors with serial numbers - * >= to this are considered. */ - unsigned long lastRequest; /* Only errors with serial numbers - * <= to this are considered. This - * field is filled in when XUnhandle - * is called. -1 means XUnhandle - * hasn't been called yet. */ - int error; /* Consider only errors with this - * error_code (-1 means consider - * all errors). */ - int request; /* Consider only errors with this - * major request code (-1 means - * consider all major codes). */ - int minorCode; /* Consider only errors with this - * minor request code (-1 means - * consider all minor codes). */ - Tk_ErrorProc *errorProc; /* Procedure to invoke when a matching - * error occurs. NULL means just ignore - * errors. */ - ClientData clientData; /* Arbitrary value to pass to - * errorProc. */ - struct TkErrorHandler *nextPtr; - /* Pointer to next older handler for - * this display, or NULL for end of - * list. */ -} TkErrorHandler; - -/* - * One of the following structures exists for each event handler - * created by calling Tk_CreateEventHandler. This information - * is used by tkEvent.c only. - */ - -typedef struct TkEventHandler { - unsigned long mask; /* Events for which to invoke - * proc. */ - Tk_EventProc *proc; /* Procedure to invoke when an event - * in mask occurs. */ - ClientData clientData; /* Argument to pass to proc. */ - struct TkEventHandler *nextPtr; - /* Next in list of handlers - * associated with window (NULL means - * end of list). */ -} TkEventHandler; - -/* - * Tk keeps one of the following data structures for each main - * window (created by a call to Tk_CreateMainWindow). It stores - * information that is shared by all of the windows associated - * with a particular main window. - */ - -typedef struct TkMainInfo { - int refCount; /* Number of windows whose "mainPtr" fields - * point here. When this becomes zero, can - * free up the structure (the reference - * count is zero because windows can get - * deleted in almost any order; the main - * window isn't necessarily the last one - * deleted). */ - struct TkWindow *winPtr; /* Pointer to main window. */ - Tcl_Interp *interp; /* Interpreter associated with application. */ - Tcl_HashTable nameTable; /* Hash table mapping path names to TkWindow - * structs for all windows related to this - * main window. Managed by tkWindow.c. */ - Tk_BindingTable bindingTable; - /* Used in conjunction with "bind" command - * to bind events to Tcl commands. */ - TkBindInfo bindInfo; /* Information used by tkBind.c on a per - * interpreter basis. */ - struct TkFontInfo *fontInfoPtr; - /* Hold named font tables. Used only by - * tkFont.c. */ - - /* - * Information used only by tkFocus.c and tk*Embed.c: - */ - - struct TkToplevelFocusInfo *tlFocusPtr; - /* First in list of records containing focus - * information for each top-level in the - * application. Used only by tkFocus.c. */ - struct TkDisplayFocusInfo *displayFocusPtr; - /* First in list of records containing focus - * information for each display that this - * application has ever used. Used only - * by tkFocus.c. */ - - struct ElArray *optionRootPtr; - /* Top level of option hierarchy for this - * main window. NULL means uninitialized. - * Managed by tkOption.c. */ - Tcl_HashTable imageTable; /* Maps from image names to Tk_ImageMaster - * structures. Managed by tkImage.c. */ - int strictMotif; /* This is linked to the tk_strictMotif - * global variable. */ - struct TkMainInfo *nextPtr; /* Next in list of all main windows managed by - * this process. */ -} TkMainInfo; - -/* - * Tk keeps the following data structure for each of it's builtin - * bitmaps. This structure is only used by tkBitmap.c and other - * platform specific bitmap files. - */ - -typedef struct { - char *source; /* Bits for bitmap. */ - int width, height; /* Dimensions of bitmap. */ - int native; /* 0 means generic (X style) bitmap, - * 1 means native style bitmap. */ -} TkPredefBitmap; - -/* - * Tk keeps one of the following structures for each window. - * Some of the information (like size and location) is a shadow - * of information managed by the X server, and some is special - * information used here, such as event and geometry management - * information. This information is (mostly) managed by tkWindow.c. - * WARNING: the declaration below must be kept consistent with the - * Tk_FakeWin structure in tk.h. If you change one, be sure to - * change the other!! - */ - -typedef struct TkWindow { - - /* - * Structural information: - */ - - Display *display; /* Display containing window. */ - TkDisplay *dispPtr; /* Tk's information about display - * for window. */ - int screenNum; /* Index of screen for window, among all - * those for dispPtr. */ - Visual *visual; /* Visual to use for window. If not default, - * MUST be set before X window is created. */ - int depth; /* Number of bits/pixel. */ - Window window; /* X's id for window. NULL means window - * hasn't actually been created yet, or it's - * been deleted. */ - struct TkWindow *childList; /* First in list of child windows, - * or NULL if no children. List is in - * stacking order, lowest window first.*/ - struct TkWindow *lastChildPtr; - /* Last in list of child windows (highest - * in stacking order), or NULL if no - * children. */ - struct TkWindow *parentPtr; /* Pointer to parent window (logical - * parent, not necessarily X parent). NULL - * means either this is the main window, or - * the window's parent has already been - * deleted. */ - struct TkWindow *nextPtr; /* Next higher sibling (in stacking order) - * in list of children with same parent. NULL - * means end of list. */ - TkMainInfo *mainPtr; /* Information shared by all windows - * associated with a particular main - * window. NULL means this window is - * a rogue that isn't associated with - * any application (at present, this - * only happens for the dummy windows - * used for "send" communication). */ - - /* - * Name and type information for the window: - */ - - char *pathName; /* Path name of window (concatenation - * of all names between this window and - * its top-level ancestor). This is a - * pointer into an entry in - * mainPtr->nameTable. NULL means that - * the window hasn't been completely - * created yet. */ - Tk_Uid nameUid; /* Name of the window within its parent - * (unique within the parent). */ - Tk_Uid classUid; /* Class of the window. NULL means window - * hasn't been given a class yet. */ - - /* - * Geometry and other attributes of window. This information - * may not be updated on the server immediately; stuff that - * hasn't been reflected in the server yet is called "dirty". - * At present, information can be dirty only if the window - * hasn't yet been created. - */ - - XWindowChanges changes; /* Geometry and other info about - * window. */ - unsigned int dirtyChanges; /* Bits indicate fields of "changes" - * that are dirty. */ - XSetWindowAttributes atts; /* Current attributes of window. */ - unsigned long dirtyAtts; /* Bits indicate fields of "atts" - * that are dirty. */ - - unsigned int flags; /* Various flag values: these are all - * defined in tk.h (confusing, but they're - * needed there for some query macros). */ - - /* - * Information kept by the event manager (tkEvent.c): - */ - - TkEventHandler *handlerList;/* First in list of event handlers - * declared for this window, or - * NULL if none. */ -#ifdef TK_USE_INPUT_METHODS - XIC inputContext; /* Input context (for input methods). */ -#endif /* TK_USE_INPUT_METHODS */ - - /* - * Information used for event bindings (see "bind" and "bindtags" - * commands in tkCmds.c): - */ - - ClientData *tagPtr; /* Points to array of tags used for bindings - * on this window. Each tag is a Tk_Uid. - * Malloc'ed. NULL means no tags. */ - int numTags; /* Number of tags at *tagPtr. */ - - /* - * Information used by tkOption.c to manage options for the - * window. - */ - - int optionLevel; /* -1 means no option information is - * currently cached for this window. - * Otherwise this gives the level in - * the option stack at which info is - * cached. */ - /* - * Information used by tkSelect.c to manage the selection. - */ - - struct TkSelHandler *selHandlerList; - /* First in list of handlers for - * returning the selection in various - * forms. */ - - /* - * Information used by tkGeometry.c for geometry management. - */ - - Tk_GeomMgr *geomMgrPtr; /* Information about geometry manager for - * this window. */ - ClientData geomData; /* Argument for geometry manager procedures. */ - int reqWidth, reqHeight; /* Arguments from last call to - * Tk_GeometryRequest, or 0's if - * Tk_GeometryRequest hasn't been - * called. */ - int internalBorderWidth; /* Width of internal border of window - * (0 means no internal border). Geometry - * managers should not normally place children - * on top of the border. */ - - /* - * Information maintained by tkWm.c for window manager communication. - */ - - struct TkWmInfo *wmInfoPtr; /* For top-level windows (and also - * for special Unix menubar and wrapper - * windows), points to structure with - * wm-related info (see tkWm.c). For - * other windows, this is NULL. */ - - /* - * Information used by widget classes. - */ - - TkClassProcs *classProcsPtr; - ClientData instanceData; - - /* - * Platform specific information private to each port. - */ - - struct TkWindowPrivate *privatePtr; -} TkWindow; - -/* - * The following structure is used as a two way map between integers - * and strings, usually to map between an internal C representation - * and the strings used in Tcl. - */ - -typedef struct TkStateMap { - int numKey; /* Integer representation of a value. */ - char *strKey; /* String representation of a value. */ -} TkStateMap; - -/* - * This structure is used by the Mac and Window porting layers as - * the internal representation of a clip_mask in a GC. - */ - -typedef struct TkpClipMask { - int type; /* One of TKP_CLIP_PIXMAP or TKP_CLIP_REGION */ - union { - Pixmap pixmap; - TkRegion region; - } value; -} TkpClipMask; - -#define TKP_CLIP_PIXMAP 0 -#define TKP_CLIP_REGION 1 - -/* - * Pointer to first entry in list of all displays currently known. - */ - -extern TkDisplay *tkDisplayList; - -/* - * Return values from TkGrabState: - */ - -#define TK_GRAB_NONE 0 -#define TK_GRAB_IN_TREE 1 -#define TK_GRAB_ANCESTOR 2 -#define TK_GRAB_EXCLUDED 3 - -/* - * The macro below is used to modify a "char" value (e.g. by casting - * it to an unsigned character) so that it can be used safely with - * macros such as isspace. - */ - -#define UCHAR(c) ((unsigned char) (c)) - -/* - * The following symbol is used in the mode field of FocusIn events - * generated by an embedded application to request the input focus from - * its container. - */ - -#define EMBEDDED_APP_WANTS_FOCUS (NotifyNormal + 20) - -/* - * Miscellaneous variables shared among Tk modules but not exported - * to the outside world: - */ - -extern Tk_Uid tkActiveUid; -extern Tk_ImageType tkBitmapImageType; -extern Tk_Uid tkDisabledUid; -extern Tk_PhotoImageFormat tkImgFmtGIF; -extern void (*tkHandleEventProc) _ANSI_ARGS_(( - XEvent* eventPtr)); -extern Tk_PhotoImageFormat tkImgFmtPPM; -extern TkMainInfo *tkMainWindowList; -extern Tk_Uid tkNormalUid; -extern Tk_ImageType tkPhotoImageType; -extern Tcl_HashTable tkPredefBitmapTable; -extern int tkSendSerial; - -/* - * Internal procedures shared among Tk modules but not exported - * to the outside world: - */ - -EXTERN char * TkAlignImageData _ANSI_ARGS_((XImage *image, - int alignment, int bitOrder)); -EXTERN TkWindow * TkAllocWindow _ANSI_ARGS_((TkDisplay *dispPtr, - int screenNum, TkWindow *parentPtr)); -EXTERN int TkAreaToPolygon _ANSI_ARGS_((double *polyPtr, - int numPoints, double *rectPtr)); -EXTERN void TkBezierPoints _ANSI_ARGS_((double control[], - int numSteps, double *coordPtr)); -EXTERN void TkBezierScreenPoints _ANSI_ARGS_((Tk_Canvas canvas, - double control[], int numSteps, - XPoint *xPointPtr)); -EXTERN void TkBindDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkBindEventProc _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN void TkBindFree _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkBindInit _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkChangeEventWindow _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *winPtr)); -#ifndef TkClipBox -EXTERN void TkClipBox _ANSI_ARGS_((TkRegion rgn, - XRectangle* rect_return)); -#endif -EXTERN int TkClipInit _ANSI_ARGS_((Tcl_Interp *interp, - TkDisplay *dispPtr)); -EXTERN void TkComputeAnchor _ANSI_ARGS_((Tk_Anchor anchor, - Tk_Window tkwin, int padX, int padY, - int innerWidth, int innerHeight, int *xPtr, - int *yPtr)); -EXTERN int TkCopyAndGlobalEval _ANSI_ARGS_((Tcl_Interp *interp, - char *script)); -EXTERN unsigned long TkCreateBindingProcedure _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_BindingTable bindingTable, - ClientData object, char *eventString, - TkBindEvalProc *evalProc, TkBindFreeProc *freeProc, - ClientData clientData)); -EXTERN Pixmap TkCreateBitmapFromData _ANSI_ARGS_((Display* display, - Drawable d, CONST char* data, - unsigned int width, unsigned int height)); -EXTERN TkCursor * TkCreateCursorFromData _ANSI_ARGS_((Tk_Window tkwin, - char *source, char *mask, int width, int height, - int xHot, int yHot, XColor fg, XColor bg)); -EXTERN int TkCreateFrame _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv, - int toplevel, char *appName)); -EXTERN Tk_Window TkCreateMainWindow _ANSI_ARGS_((Tcl_Interp *interp, - char *screenName, char *baseName)); -#ifndef TkCreateRegion -EXTERN TkRegion TkCreateRegion _ANSI_ARGS_((void)); -#endif -EXTERN Time TkCurrentTime _ANSI_ARGS_((TkDisplay *dispPtr)); -EXTERN int TkDeadAppCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN void TkDeleteAllImages _ANSI_ARGS_((TkMainInfo *mainPtr)); -#ifndef TkDestroyRegion -EXTERN void TkDestroyRegion _ANSI_ARGS_((TkRegion rgn)); -#endif -EXTERN void TkDoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkDrawInsetFocusHighlight _ANSI_ARGS_(( - Tk_Window tkwin, GC gc, int width, - Drawable drawable, int padding)); -EXTERN void TkEventCleanupProc _ANSI_ARGS_(( - ClientData clientData, Tcl_Interp *interp)); -EXTERN void TkEventDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkFillPolygon _ANSI_ARGS_((Tk_Canvas canvas, - double *coordPtr, int numPoints, Display *display, - Drawable drawable, GC gc, GC outlineGC)); -EXTERN int TkFindStateNum _ANSI_ARGS_((Tcl_Interp *interp, - CONST char *option, CONST TkStateMap *mapPtr, - CONST char *strKey)); -EXTERN char * TkFindStateString _ANSI_ARGS_(( - CONST TkStateMap *mapPtr, int numKey)); -EXTERN void TkFocusDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkFocusFilterEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN TkWindow * TkFocusKeyEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN void TkFontPkgInit _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkFontPkgFree _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkFreeBindingTags _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkFreeCursor _ANSI_ARGS_((TkCursor *cursorPtr)); -EXTERN void TkFreeWindowId _ANSI_ARGS_((TkDisplay *dispPtr, - Window w)); -EXTERN void TkGenerateActivateEvents _ANSI_ARGS_(( - TkWindow *winPtr, int active)); -EXTERN char * TkGetBitmapData _ANSI_ARGS_((Tcl_Interp *interp, - char *string, char *fileName, int *widthPtr, - int *heightPtr, int *hotXPtr, int *hotYPtr)); -EXTERN void TkGetButtPoints _ANSI_ARGS_((double p1[], double p2[], - double width, int project, double m1[], - double m2[])); -EXTERN TkCursor * TkGetCursorByName _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN char * TkGetDefaultScreenName _ANSI_ARGS_((Tcl_Interp *interp, - char *screenName)); -EXTERN TkDisplay * TkGetDisplay _ANSI_ARGS_((Display *display)); -EXTERN int TkGetDisplayOf _ANSI_ARGS_((Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[], - Tk_Window *tkwinPtr)); -EXTERN TkWindow * TkGetFocusWin _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkGetInterpNames _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN int TkGetMiterPoints _ANSI_ARGS_((double p1[], double p2[], - double p3[], double width, double m1[], - double m2[])); -#ifndef TkGetNativeProlog -EXTERN int TkGetNativeProlog _ANSI_ARGS_((Tcl_Interp *interp)); -#endif -EXTERN void TkGetPointerCoords _ANSI_ARGS_((Tk_Window tkwin, - int *xPtr, int *yPtr)); -EXTERN int TkGetProlog _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void TkGetServerInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN void TkGrabDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkGrabState _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN TkWindow * TkIDToWindow _ANSI_ARGS_((Window window, - TkDisplay *display)); -EXTERN void TkIncludePoint _ANSI_ARGS_((Tk_Item *itemPtr, - double *pointPtr)); -EXTERN void TkInitXId _ANSI_ARGS_((TkDisplay *dispPtr)); -EXTERN void TkInOutEvents _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *sourcePtr, TkWindow *destPtr, - int leaveType, int enterType, - Tcl_QueuePosition position)); -EXTERN void TkInstallFrameMenu _ANSI_ARGS_((Tk_Window tkwin)); -#ifndef TkIntersectRegion -EXTERN void TkIntersectRegion _ANSI_ARGS_((TkRegion sra, - TkRegion srcb, TkRegion dr_return)); -#endif -EXTERN char * TkKeysymToString _ANSI_ARGS_((KeySym keysym)); -EXTERN int TkLineToArea _ANSI_ARGS_((double end1Ptr[2], - double end2Ptr[2], double rectPtr[4])); -EXTERN double TkLineToPoint _ANSI_ARGS_((double end1Ptr[2], - double end2Ptr[2], double pointPtr[2])); -EXTERN int TkListAppend _ANSI_ARGS_((void **headPtrPtr, - void *itemPtr, size_t size)); -EXTERN int TkListDelete _ANSI_ARGS_((void **headPtrPtr, - void *itemPtr, size_t size)); -EXTERN void * TkListFind _ANSI_ARGS_((void *headPtr, void *itemPtr, - size_t size)); -EXTERN int TkMakeBezierCurve _ANSI_ARGS_((Tk_Canvas canvas, - double *pointPtr, int numPoints, int numSteps, - XPoint xPoints[], double dblPoints[])); -EXTERN void TkMakeBezierPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, double *pointPtr, - int numPoints)); -EXTERN void TkOptionClassChanged _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkOptionDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkOvalToArea _ANSI_ARGS_((double *ovalPtr, - double *rectPtr)); -EXTERN double TkOvalToPoint _ANSI_ARGS_((double ovalPtr[4], - double width, int filled, double pointPtr[2])); -EXTERN int TkpChangeFocus _ANSI_ARGS_((TkWindow *winPtr, - int force)); -EXTERN void TkpCloseDisplay _ANSI_ARGS_((TkDisplay *dispPtr)); -EXTERN void TkpClaimFocus _ANSI_ARGS_((TkWindow *topLevelPtr, - int force)); -#ifndef TkpCmapStressed -EXTERN int TkpCmapStressed _ANSI_ARGS_((Tk_Window tkwin, - Colormap colormap)); -#endif -#ifndef TkpCreateNativeBitmap -EXTERN Pixmap TkpCreateNativeBitmap _ANSI_ARGS_((Display *display, - char * source)); -#endif -#ifndef TkpDefineNativeBitmaps -EXTERN void TkpDefineNativeBitmaps _ANSI_ARGS_((void)); -#endif -EXTERN void TkpDisplayWarning _ANSI_ARGS_((char *msg, - char *title)); -EXTERN void TkpGetAppName _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_DString *name)); -EXTERN unsigned long TkpGetMS _ANSI_ARGS_((void)); -#ifndef TkpGetNativeAppBitmap -EXTERN Pixmap TkpGetNativeAppBitmap _ANSI_ARGS_((Display *display, - char *name, int *width, int *height)); -#endif -EXTERN TkWindow * TkpGetOtherWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN TkWindow * TkpGetWrapperWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkpInit _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void TkpInitializeMenuBindings _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_BindingTable bindingTable)); -EXTERN void TkpMakeContainer _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkpMakeMenuWindow _ANSI_ARGS_((Tk_Window tkwin, - int transient)); -EXTERN Window TkpMakeWindow _ANSI_ARGS_((TkWindow *winPtr, - Window parent)); -EXTERN void TkpMenuNotifyToplevelCreate _ANSI_ARGS_(( - Tcl_Interp *, char *menuName)); -EXTERN TkDisplay * TkpOpenDisplay _ANSI_ARGS_((char *display_name)); -EXTERN void TkPointerDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkPointerEvent _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *winPtr)); -EXTERN int TkPolygonToArea _ANSI_ARGS_((double *polyPtr, - int numPoints, double *rectPtr)); -EXTERN double TkPolygonToPoint _ANSI_ARGS_((double *polyPtr, - int numPoints, double *pointPtr)); -EXTERN int TkPositionInTree _ANSI_ARGS_((TkWindow *winPtr, - TkWindow *treePtr)); -#ifndef TkpPrintWindowId -EXTERN void TkpPrintWindowId _ANSI_ARGS_((char *buf, - Window window)); -#endif -EXTERN void TkpRedirectKeyEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -#ifndef TkpScanWindowId -EXTERN int TkpScanWindowId _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *idPtr)); -#endif -EXTERN void TkpSetCapture _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkpSetCursor _ANSI_ARGS_((TkpCursor cursor)); -EXTERN void TkpSetMainMenubar _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *menuName)); -#ifndef TkpSync -EXTERN void TkpSync _ANSI_ARGS_((Display *display)); -#endif -EXTERN int TkpTestembedCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int TkpUseWindow _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string)); -#ifndef TkPutImage -EXTERN void TkPutImage _ANSI_ARGS_((unsigned long *colors, - int ncolors, Display* display, Drawable d, - GC gc, XImage* image, int src_x, int src_y, - int dest_x, int dest_y, unsigned int width, - unsigned int height)); -#endif -EXTERN int TkpWindowWasRecentlyDeleted _ANSI_ARGS_((Window win, - TkDisplay *dispPtr)); -EXTERN void TkpWmSetState _ANSI_ARGS_((TkWindow *winPtr, - int state)); -EXTERN void TkQueueEventForAllChildren _ANSI_ARGS_(( - TkWindow *winPtr, XEvent *eventPtr)); -EXTERN int TkReadBitmapFile _ANSI_ARGS_((Display* display, - Drawable d, CONST char* filename, - unsigned int* width_return, - unsigned int* height_return, - Pixmap* bitmap_return, - int* x_hot_return, int* y_hot_return)); -#ifndef TkRectInRegion -EXTERN int TkRectInRegion _ANSI_ARGS_((TkRegion rgn, - int x, int y, unsigned int width, - unsigned int height)); -#endif -EXTERN int TkScrollWindow _ANSI_ARGS_((Tk_Window tkwin, GC gc, - int x, int y, int width, int height, int dx, - int dy, TkRegion damageRgn)); -EXTERN void TkSelDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkSelEventProc _ANSI_ARGS_((Tk_Window tkwin, - XEvent *eventPtr)); -EXTERN void TkSelInit _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkSelPropProc _ANSI_ARGS_((XEvent *eventPtr)); -EXTERN void TkSetClassProcs _ANSI_ARGS_((Tk_Window tkwin, - TkClassProcs *procs, ClientData instanceData)); -#ifndef TkSetPixmapColormap -EXTERN void TkSetPixmapColormap _ANSI_ARGS_((Pixmap pixmap, - Colormap colormap)); -#endif -#ifndef TkSetRegion -EXTERN void TkSetRegion _ANSI_ARGS_((Display* display, GC gc, - TkRegion rgn)); -#endif -EXTERN void TkSetWindowMenuBar _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *oldMenuName, - char *menuName)); -EXTERN KeySym TkStringToKeysym _ANSI_ARGS_((char *name)); -EXTERN int TkThickPolyLineToArea _ANSI_ARGS_((double *coordPtr, - int numPoints, double width, int capStyle, - int joinStyle, double *rectPtr)); -#ifndef TkUnionRectWithRegion -EXTERN void TkUnionRectWithRegion _ANSI_ARGS_((XRectangle* rect, - TkRegion src, TkRegion dr_return)); -#endif -EXTERN void TkWmAddToColormapWindows _ANSI_ARGS_(( - TkWindow *winPtr)); -EXTERN void TkWmDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN TkWindow * TkWmFocusToplevel _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmMapWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmNewWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmProtocolEventProc _ANSI_ARGS_((TkWindow *winPtr, - XEvent *evenvPtr)); -EXTERN void TkWmRemoveFromColormapWindows _ANSI_ARGS_(( - TkWindow *winPtr)); -EXTERN void TkWmRestackToplevel _ANSI_ARGS_((TkWindow *winPtr, - int aboveBelow, TkWindow *otherPtr)); -EXTERN void TkWmSetClass _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmUnmapWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkXFileProc _ANSI_ARGS_((ClientData clientData, - int mask, int flags)); - -/* - * Unsupported commands. - */ -EXTERN int TkUnsupported1Cmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKINT */ diff --git a/generic/tkListbox.c b/generic/tkListbox.c deleted file mode 100644 index 34189c7..0000000 --- a/generic/tkListbox.c +++ /dev/null @@ -1,2335 +0,0 @@ -/* - * tkListbox.c -- - * - * This module implements listbox widgets for the Tk - * toolkit. A listbox displays a collection of strings, - * one per line, and provides scrolling and selection. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkListbox.c,v 1.2 1998/09/14 18:23:13 stanton Exp $ - */ - -#include "tkPort.h" -#include "default.h" -#include "tkInt.h" - -/* - * One record of the following type is kept for each element - * associated with a listbox widget: - */ - -typedef struct Element { - int textLength; /* # non-NULL characters in text. */ - int lBearing; /* Distance from first character's - * origin to left edge of character. */ - int pixelWidth; /* Total width of element in pixels (including - * left bearing and right bearing). */ - int selected; /* 1 means this item is selected, 0 means - * it isn't. */ - struct Element *nextPtr; /* Next in list of all elements of this - * listbox, or NULL for last element. */ - char text[4]; /* Characters of this element, NULL- - * terminated. The actual space allocated - * here will be as large as needed (> 4, - * most likely). Must be the last field - * of the record. */ -} Element; - -#define ElementSize(stringLength) \ - ((unsigned) (sizeof(Element) - 3 + stringLength)) - -/* - * A data structure of the following type is kept for each listbox - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the listbox. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with listbox. */ - Tcl_Command widgetCmd; /* Token for listbox's widget command. */ - int numElements; /* Total number of elements in this listbox. */ - Element *firstPtr; /* First in list of elements (NULL if no - * elements). */ - Element *lastPtr; /* Last in list of elements (NULL if no - * elements). */ - - /* - * Information used when displaying widget: - */ - - Tk_3DBorder normalBorder; /* Used for drawing border around whole - * window, plus used for background. */ - int borderWidth; /* Width of 3-D border around window. */ - int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *fgColorPtr; /* Text color in normal mode. */ - GC textGC; /* For drawing normal text. */ - Tk_3DBorder selBorder; /* Borders and backgrounds for selected - * elements. */ - int selBorderWidth; /* Width of border around selection. */ - XColor *selFgColorPtr; /* Foreground color for selected elements. */ - GC selTextGC; /* For drawing selected text. */ - int width; /* Desired width of window, in characters. */ - int height; /* Desired height of window, in lines. */ - int lineHeight; /* Number of pixels allocated for each line - * in display. */ - int topIndex; /* Index of top-most element visible in - * window. */ - int fullLines; /* Number of lines that fit are completely - * visible in window. There may be one - * additional line at the bottom that is - * partially visible. */ - int partialLine; /* 0 means that the window holds exactly - * fullLines lines. 1 means that there is - * one additional line that is partially - * visble. */ - int setGrid; /* Non-zero means pass gridding information - * to window manager. */ - - /* - * Information to support horizontal scrolling: - */ - - int maxWidth; /* Width (in pixels) of widest string in - * listbox. */ - int xScrollUnit; /* Number of pixels in one "unit" for - * horizontal scrolling (window scrolls - * horizontally in increments of this size). - * This is an average character size. */ - int xOffset; /* The left edge of each string in the - * listbox is offset to the left by this - * many pixels (0 means no offset, positive - * means there is an offset). */ - - /* - * Information about what's selected or active, if any. - */ - - Tk_Uid selectMode; /* Selection style: single, browse, multiple, - * or extended. This value isn't used in C - * code, but the Tcl bindings use it. */ - int numSelected; /* Number of elements currently selected. */ - int selectAnchor; /* Fixed end of selection (i.e. element - * at which selection was started.) */ - int exportSelection; /* Non-zero means tie internal listbox - * to X selection. */ - int active; /* Index of "active" element (the one that - * has been selected by keyboard traversal). - * -1 means none. */ - - /* - * Information for scanning: - */ - - int scanMarkX; /* X-position at which scan started (e.g. - * button was pressed here). */ - int scanMarkY; /* Y-position at which scan started (e.g. - * button was pressed here). */ - int scanMarkXOffset; /* Value of "xOffset" field when scan - * started. */ - int scanMarkYIndex; /* Index of line that was at top of window - * when scan started. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - char *yScrollCmd; /* Command prefix for communicating with - * vertical scrollbar. NULL means no command - * to issue. Malloc'ed. */ - char *xScrollCmd; /* Command prefix for communicating with - * horizontal scrollbar. NULL means no command - * to issue. Malloc'ed. */ - int flags; /* Various flag bits: see below for - * definitions. */ -} Listbox; - -/* - * Flag bits for listboxes: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * UPDATE_V_SCROLLBAR: Non-zero means vertical scrollbar needs - * to be updated. - * UPDATE_H_SCROLLBAR: Non-zero means horizontal scrollbar needs - * to be updated. - * GOT_FOCUS: Non-zero means this widget currently - * has the input focus. - */ - -#define REDRAW_PENDING 1 -#define UPDATE_V_SCROLLBAR 2 -#define UPDATE_H_SCROLLBAR 4 -#define GOT_FOCUS 8 - -/* - * Information used for argv parsing: - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_LISTBOX_BG_COLOR, Tk_Offset(Listbox, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_LISTBOX_BG_MONO, Tk_Offset(Listbox, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_LISTBOX_BORDER_WIDTH, Tk_Offset(Listbox, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_LISTBOX_CURSOR, Tk_Offset(Listbox, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_LISTBOX_EXPORT_SELECTION, - Tk_Offset(Listbox, exportSelection), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_LISTBOX_FONT, Tk_Offset(Listbox, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_LISTBOX_FG, Tk_Offset(Listbox, fgColorPtr), 0}, - {TK_CONFIG_INT, "-height", "height", "Height", - DEF_LISTBOX_HEIGHT, Tk_Offset(Listbox, height), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_LISTBOX_HIGHLIGHT_BG, - Tk_Offset(Listbox, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_LISTBOX_HIGHLIGHT, Tk_Offset(Listbox, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_LISTBOX_HIGHLIGHT_WIDTH, Tk_Offset(Listbox, highlightWidth), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_LISTBOX_RELIEF, Tk_Offset(Listbox, relief), 0}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_LISTBOX_SELECT_COLOR, Tk_Offset(Listbox, selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_LISTBOX_SELECT_MONO, Tk_Offset(Listbox, selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_LISTBOX_SELECT_BD, Tk_Offset(Listbox, selBorderWidth), 0}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_LISTBOX_SELECT_FG_COLOR, Tk_Offset(Listbox, selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_LISTBOX_SELECT_FG_MONO, Tk_Offset(Listbox, selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode", - DEF_LISTBOX_SELECT_MODE, Tk_Offset(Listbox, selectMode), 0}, - {TK_CONFIG_BOOLEAN, "-setgrid", "setGrid", "SetGrid", - DEF_LISTBOX_SET_GRID, Tk_Offset(Listbox, setGrid), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_LISTBOX_TAKE_FOCUS, Tk_Offset(Listbox, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-width", "width", "Width", - DEF_LISTBOX_WIDTH, Tk_Offset(Listbox, width), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_LISTBOX_SCROLL_COMMAND, Tk_Offset(Listbox, xScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", - DEF_LISTBOX_SCROLL_COMMAND, Tk_Offset(Listbox, yScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void ChangeListboxOffset _ANSI_ARGS_((Listbox *listPtr, - int offset)); -static void ChangeListboxView _ANSI_ARGS_((Listbox *listPtr, - int index)); -static int ConfigureListbox _ANSI_ARGS_((Tcl_Interp *interp, - Listbox *listPtr, int argc, char **argv, - int flags)); -static void DeleteEls _ANSI_ARGS_((Listbox *listPtr, int first, - int last)); -static void DestroyListbox _ANSI_ARGS_((char *memPtr)); -static void DisplayListbox _ANSI_ARGS_((ClientData clientData)); -static int GetListboxIndex _ANSI_ARGS_((Tcl_Interp *interp, - Listbox *listPtr, char *string, int endIsSize, - int *indexPtr)); -static void InsertEls _ANSI_ARGS_((Listbox *listPtr, int index, - int argc, char **argv)); -static void ListboxCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void ListboxComputeGeometry _ANSI_ARGS_((Listbox *listPtr, - int fontChanged, int maxIsStale, int updateGrid)); -static void ListboxEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int ListboxFetchSelection _ANSI_ARGS_(( - ClientData clientData, int offset, char *buffer, - int maxBytes)); -static void ListboxLostSelection _ANSI_ARGS_(( - ClientData clientData)); -static void ListboxRedrawRange _ANSI_ARGS_((Listbox *listPtr, - int first, int last)); -static void ListboxScanTo _ANSI_ARGS_((Listbox *listPtr, - int x, int y)); -static void ListboxSelect _ANSI_ARGS_((Listbox *listPtr, - int first, int last, int select)); -static void ListboxUpdateHScrollbar _ANSI_ARGS_((Listbox *listPtr)); -static void ListboxUpdateVScrollbar _ANSI_ARGS_((Listbox *listPtr)); -static int ListboxWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void ListboxWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static int NearestListboxElement _ANSI_ARGS_((Listbox *listPtr, - int y)); - -/* - * The structure below defines button class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs listboxClass = { - NULL, /* createProc. */ - ListboxWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_ListboxCmd -- - * - * This procedure is invoked to process the "listbox" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_ListboxCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Listbox *listPtr; - Tk_Window new; - Tk_Window tkwin = (Tk_Window) clientData; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - /* - * Initialize the fields of the structure that won't be initialized - * by ConfigureListbox, or that ConfigureListbox requires to be - * initialized already (e.g. resource pointers). - */ - - listPtr = (Listbox *) ckalloc(sizeof(Listbox)); - listPtr->tkwin = new; - listPtr->display = Tk_Display(new); - listPtr->interp = interp; - listPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(listPtr->tkwin), ListboxWidgetCmd, - (ClientData) listPtr, ListboxCmdDeletedProc); - listPtr->numElements = 0; - listPtr->firstPtr = NULL; - listPtr->lastPtr = NULL; - listPtr->normalBorder = NULL; - listPtr->borderWidth = 0; - listPtr->relief = TK_RELIEF_RAISED; - listPtr->highlightWidth = 0; - listPtr->highlightBgColorPtr = NULL; - listPtr->highlightColorPtr = NULL; - listPtr->inset = 0; - listPtr->tkfont = NULL; - listPtr->fgColorPtr = NULL; - listPtr->textGC = None; - listPtr->selBorder = NULL; - listPtr->selBorderWidth = 0; - listPtr->selFgColorPtr = None; - listPtr->selTextGC = None; - listPtr->width = 0; - listPtr->height = 0; - listPtr->lineHeight = 0; - listPtr->topIndex = 0; - listPtr->fullLines = 1; - listPtr->partialLine = 0; - listPtr->setGrid = 0; - listPtr->maxWidth = 0; - listPtr->xScrollUnit = 1; - listPtr->xOffset = 0; - listPtr->selectMode = NULL; - listPtr->numSelected = 0; - listPtr->selectAnchor = 0; - listPtr->exportSelection = 1; - listPtr->active = 0; - listPtr->scanMarkX = 0; - listPtr->scanMarkY = 0; - listPtr->scanMarkXOffset = 0; - listPtr->scanMarkYIndex = 0; - listPtr->cursor = None; - listPtr->takeFocus = NULL; - listPtr->xScrollCmd = NULL; - listPtr->yScrollCmd = NULL; - listPtr->flags = 0; - - Tk_SetClass(listPtr->tkwin, "Listbox"); - TkSetClassProcs(listPtr->tkwin, &listboxClass, (ClientData) listPtr); - Tk_CreateEventHandler(listPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - ListboxEventProc, (ClientData) listPtr); - Tk_CreateSelHandler(listPtr->tkwin, XA_PRIMARY, XA_STRING, - ListboxFetchSelection, (ClientData) listPtr, XA_STRING); - if (ConfigureListbox(interp, listPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - interp->result = Tk_PathName(listPtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(listPtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * ListboxWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ListboxWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about listbox widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Listbox *listPtr = (Listbox *) clientData; - int result = TCL_OK; - size_t length; - int c; - Tk_FontMetrics fm; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) listPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " activate index\"", - (char *) NULL); - goto error; - } - ListboxRedrawRange(listPtr, listPtr->active, listPtr->active); - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; - } - if (index < 0) { - index = 0; - } - listPtr->active = index; - ListboxRedrawRange(listPtr, listPtr->active, listPtr->active); - } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - int index, x, y, i; - Element *elPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox index\"", (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if ((index >= listPtr->numElements) || (index < 0)) { - goto done; - } - for (i = 0, elPtr = listPtr->firstPtr; i < index; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - if ((index >= listPtr->topIndex) && (index < listPtr->numElements) - && (index < (listPtr->topIndex + listPtr->fullLines - + listPtr->partialLine))) { - x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; - y = ((index - listPtr->topIndex)*listPtr->lineHeight) - + listPtr->inset + listPtr->selBorderWidth; - Tk_GetFontMetrics(listPtr->tkfont, &fm); - sprintf(interp->result, "%d %d %d %d", x, y, elPtr->pixelWidth, - fm.linespace); - } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, argv[2], 0); - } else { - result = ConfigureListbox(interp, listPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'c') && (strncmp(argv[1], "curselection", length) == 0) - && (length >= 2)) { - int i, count; - char index[20]; - Element *elPtr; - - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " curselection\"", - (char *) NULL); - goto error; - } - count = 0; - for (i = 0, elPtr = listPtr->firstPtr; elPtr != NULL; - i++, elPtr = elPtr->nextPtr) { - if (elPtr->selected) { - sprintf(index, "%d", i); - Tcl_AppendElement(interp, index); - count++; - } - } - if (count != listPtr->numSelected) { - panic("ListboxWidgetCmd: selection count incorrect"); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; - - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete firstIndex ?lastIndex?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &first) != TCL_OK) { - goto error; - } - if (first < listPtr->numElements) { - if (argc == 3) { - last = first; - } else { - if (GetListboxIndex(interp, listPtr, argv[3], 0, - &last) != TCL_OK) { - goto error; - } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; - } - } - DeleteEls(listPtr, first, last); - } - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - int first, last, i; - Element *elPtr; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get first ?last?\"", (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &first) != TCL_OK) { - goto error; - } - if ((argc == 4) && (GetListboxIndex(interp, listPtr, argv[3], - 0, &last) != TCL_OK)) { - goto error; - } - if (first >= listPtr->numElements) { - goto done; - } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; - } - - for (elPtr = listPtr->firstPtr, i = 0; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - if (elPtr != NULL) { - if (argc == 3) { - if (first >= 0) { - interp->result = elPtr->text; - } - } else { - for ( ; i <= last; i++, elPtr = elPtr->nextPtr) { - Tcl_AppendElement(interp, elPtr->text); - } - } - } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index index\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 1, &index) - != TCL_OK) { - goto error; - } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int index; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index ?element element ...?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 1, &index) - != TCL_OK) { - goto error; - } - InsertEls(listPtr, index, argc-3, argv+3); - } else if ((c == 'n') && (strncmp(argv[1], "nearest", length) == 0)) { - int index, y; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " nearest y\"", (char *) NULL); - goto error; - } - if (Tcl_GetInt(interp, argv[2], &y) != TCL_OK) { - goto error; - } - index = NearestListboxElement(listPtr, y); - sprintf(interp->result, "%d", index); - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "scan", length) == 0)) { - int x, y; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { - goto error; - } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { - listPtr->scanMarkX = x; - listPtr->scanMarkY = y; - listPtr->scanMarkXOffset = listPtr->xOffset; - listPtr->scanMarkYIndex = listPtr->topIndex; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { - ListboxScanTo(listPtr, x, y); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; - } - } else if ((c == 's') && (strncmp(argv[1], "see", length) == 0) - && (length >= 3)) { - int index, diff; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " see index\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; - } - if (index < 0) { - index = 0; - } - diff = listPtr->topIndex-index; - if (diff > 0) { - if (diff <= (listPtr->fullLines/3)) { - ChangeListboxView(listPtr, index); - } else { - ChangeListboxView(listPtr, index - (listPtr->fullLines-1)/2); - } - } else { - diff = index - (listPtr->topIndex + listPtr->fullLines - 1); - if (diff > 0) { - if (diff <= (listPtr->fullLines/3)) { - ChangeListboxView(listPtr, listPtr->topIndex + diff); - } else { - ChangeListboxView(listPtr, - index - (listPtr->fullLines-1)/2); - } - } - } - } else if ((c == 's') && (length >= 3) - && (strncmp(argv[1], "selection", length) == 0)) { - int first, last; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection option index ?index?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[3], 0, &first) != TCL_OK) { - goto error; - } - if (argc == 5) { - if (GetListboxIndex(interp, listPtr, argv[4], 0, &last) != TCL_OK) { - goto error; - } - } else { - last = first; - } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'a') && (strncmp(argv[2], "anchor", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection anchor index\"", (char *) NULL); - goto error; - } - if (first >= listPtr->numElements) { - first = listPtr->numElements-1; - } - if (first < 0) { - first = 0; - } - listPtr->selectAnchor = first; - } else if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) { - ListboxSelect(listPtr, first, last, 0); - } else if ((c == 'i') && (strncmp(argv[2], "includes", length) == 0)) { - int i; - Element *elPtr; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection includes index\"", (char *) NULL); - goto error; - } - if ((first < 0) || (first >= listPtr->numElements)) { - interp->result = "0"; - goto done; - } - for (elPtr = listPtr->firstPtr, i = 0; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - if (elPtr->selected) { - interp->result = "1"; - } else { - interp->result = "0"; - } - } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) { - ListboxSelect(listPtr, first, last, 1); - } else { - Tcl_AppendResult(interp, "bad selection option \"", argv[2], - "\": must be anchor, clear, includes, or set", - (char *) NULL); - goto error; - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "size", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " size\"", (char *) NULL); - goto error; - } - sprintf(interp->result, "%d", listPtr->numElements); - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - int index, count, type, windowWidth, windowUnits; - int offset = 0; /* Initialized to stop gcc warnings. */ - double fraction, fraction2; - - windowWidth = Tk_Width(listPtr->tkwin) - - 2*(listPtr->inset + listPtr->selBorderWidth); - if (argc == 2) { - if (listPtr->maxWidth == 0) { - interp->result = "0 1"; - } else { - fraction = listPtr->xOffset/((double) listPtr->maxWidth); - fraction2 = (listPtr->xOffset + windowWidth) - /((double) listPtr->maxWidth); - if (fraction2 > 1.0) { - fraction2 = 1.0; - } - sprintf(interp->result, "%g %g", fraction, fraction2); - } - } else if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) { - goto error; - } - ChangeListboxOffset(listPtr, index*listPtr->xScrollUnit); - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - offset = (int) (fraction*listPtr->maxWidth + 0.5); - break; - case TK_SCROLL_PAGES: - windowUnits = windowWidth/listPtr->xScrollUnit; - if (windowUnits > 2) { - offset = listPtr->xOffset - + count*listPtr->xScrollUnit*(windowUnits-2); - } else { - offset = listPtr->xOffset + count*listPtr->xScrollUnit; - } - break; - case TK_SCROLL_UNITS: - offset = listPtr->xOffset + count*listPtr->xScrollUnit; - break; - } - ChangeListboxOffset(listPtr, offset); - } - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) { - int index, count, type; - double fraction, fraction2; - - if (argc == 2) { - if (listPtr->numElements == 0) { - interp->result = "0 1"; - } else { - fraction = listPtr->topIndex/((double) listPtr->numElements); - fraction2 = (listPtr->topIndex+listPtr->fullLines) - /((double) listPtr->numElements); - if (fraction2 > 1.0) { - fraction2 = 1.0; - } - sprintf(interp->result, "%g %g", fraction, fraction2); - } - } else if (argc == 3) { - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) - != TCL_OK) { - goto error; - } - ChangeListboxView(listPtr, index); - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - index = (int) (listPtr->numElements*fraction + 0.5); - break; - case TK_SCROLL_PAGES: - if (listPtr->fullLines > 2) { - index = listPtr->topIndex - + count*(listPtr->fullLines-2); - } else { - index = listPtr->topIndex + count; - } - break; - case TK_SCROLL_UNITS: - index = listPtr->topIndex + count; - break; - } - ChangeListboxView(listPtr, index); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be activate, bbox, cget, configure, ", - "curselection, delete, get, index, insert, nearest, ", - "scan, see, selection, size, ", - "xview, or yview", (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) listPtr); - return result; - - error: - Tcl_Release((ClientData) listPtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyListbox -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a listbox at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the listbox is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyListbox(memPtr) - char *memPtr; /* Info about listbox widget. */ -{ - register Listbox *listPtr = (Listbox *) memPtr; - register Element *elPtr, *nextPtr; - - /* - * Free up all of the list elements. - */ - - for (elPtr = listPtr->firstPtr; elPtr != NULL; ) { - nextPtr = elPtr->nextPtr; - ckfree((char *) elPtr); - elPtr = nextPtr; - } - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (listPtr->textGC != None) { - Tk_FreeGC(listPtr->display, listPtr->textGC); - } - if (listPtr->selTextGC != None) { - Tk_FreeGC(listPtr->display, listPtr->selTextGC); - } - Tk_FreeOptions(configSpecs, (char *) listPtr, listPtr->display, 0); - ckfree((char *) listPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureListbox -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or reconfigure) - * a listbox widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for listPtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureListbox(interp, listPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register Listbox *listPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - int oldExport; - - oldExport = listPtr->exportSelection; - if (Tk_ConfigureWidget(interp, listPtr->tkwin, configSpecs, - argc, argv, (char *) listPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few options need special processing, such as setting the - * background from a 3-D border. - */ - - Tk_SetBackgroundFromBorder(listPtr->tkwin, listPtr->normalBorder); - - if (listPtr->highlightWidth < 0) { - listPtr->highlightWidth = 0; - } - listPtr->inset = listPtr->highlightWidth + listPtr->borderWidth; - - /* - * Claim the selection if we've suddenly started exporting it and - * there is a selection to export. - */ - - if (listPtr->exportSelection && !oldExport - && (listPtr->numSelected != 0)) { - Tk_OwnSelection(listPtr->tkwin, XA_PRIMARY, ListboxLostSelection, - (ClientData) listPtr); - } - - ListboxWorldChanged((ClientData) listPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ListboxWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Listbox will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -ListboxWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC gc; - unsigned long mask; - Listbox *listPtr; - - listPtr = (Listbox *) instanceData; - - gcValues.foreground = listPtr->fgColorPtr->pixel; - gcValues.font = Tk_FontId(listPtr->tkfont); - gcValues.graphics_exposures = False; - mask = GCForeground | GCFont | GCGraphicsExposures; - gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); - if (listPtr->textGC != None) { - Tk_FreeGC(listPtr->display, listPtr->textGC); - } - listPtr->textGC = gc; - - gcValues.foreground = listPtr->selFgColorPtr->pixel; - gcValues.font = Tk_FontId(listPtr->tkfont); - mask = GCForeground | GCFont; - gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); - if (listPtr->selTextGC != None) { - Tk_FreeGC(listPtr->display, listPtr->selTextGC); - } - listPtr->selTextGC = gc; - - /* - * Register the desired geometry for the window and arrange for - * the window to be redisplayed. - */ - - ListboxComputeGeometry(listPtr, 1, 1, 1); - listPtr->flags |= UPDATE_V_SCROLLBAR|UPDATE_H_SCROLLBAR; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); -} - -/* - *-------------------------------------------------------------- - * - * DisplayListbox -- - * - * This procedure redraws the contents of a listbox window. - * - * Results: - * None. - * - * Side effects: - * Information appears on the screen. - * - *-------------------------------------------------------------- - */ - -static void -DisplayListbox(clientData) - ClientData clientData; /* Information about window. */ -{ - register Listbox *listPtr = (Listbox *) clientData; - register Tk_Window tkwin = listPtr->tkwin; - register Element *elPtr; - GC gc; - int i, limit, x, y, width, prevSelected; - Tk_FontMetrics fm; - int left, right; /* Non-zero values here indicate - * that the left or right edge of - * the listbox is off-screen. */ - Pixmap pixmap; - - listPtr->flags &= ~REDRAW_PENDING; - if (listPtr->flags & UPDATE_V_SCROLLBAR) { - ListboxUpdateVScrollbar(listPtr); - } - if (listPtr->flags & UPDATE_H_SCROLLBAR) { - ListboxUpdateHScrollbar(listPtr); - } - listPtr->flags &= ~(REDRAW_PENDING|UPDATE_V_SCROLLBAR|UPDATE_H_SCROLLBAR); - if ((listPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { - return; - } - - /* - * Redrawing is done in a temporary pixmap that is allocated - * here and freed at the end of the procedure. All drawing is - * done to the pixmap, and the pixmap is copied to the screen - * at the end of the procedure. This provides the smoothest - * possible visual effects (no flashing on the screen). - */ - - pixmap = Tk_GetPixmap(listPtr->display, Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); - Tk_Fill3DRectangle(tkwin, pixmap, listPtr->normalBorder, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - - /* - * Iterate through all of the elements of the listbox, displaying each - * in turn. Selected elements use a different GC and have a raised - * background. - */ - - limit = listPtr->topIndex + listPtr->fullLines + listPtr->partialLine - 1; - if (limit >= listPtr->numElements) { - limit = listPtr->numElements-1; - } - left = right = 0; - if (listPtr->xOffset > 0) { - left = listPtr->selBorderWidth+1; - } - if ((listPtr->maxWidth - listPtr->xOffset) > (Tk_Width(listPtr->tkwin) - - 2*(listPtr->inset + listPtr->selBorderWidth))) { - right = listPtr->selBorderWidth+1; - } - prevSelected = 0; - for (elPtr = listPtr->firstPtr, i = 0; (elPtr != NULL) && (i <= limit); - prevSelected = elPtr->selected, elPtr = elPtr->nextPtr, i++) { - if (i < listPtr->topIndex) { - continue; - } - x = listPtr->inset; - y = ((i - listPtr->topIndex) * listPtr->lineHeight) - + listPtr->inset; - gc = listPtr->textGC; - if (elPtr->selected) { - gc = listPtr->selTextGC; - width = Tk_Width(tkwin) - 2*listPtr->inset; - Tk_Fill3DRectangle(tkwin, pixmap, listPtr->selBorder, x, y, - width, listPtr->lineHeight, 0, TK_RELIEF_FLAT); - - /* - * Draw beveled edges around the selection, if there are visible - * edges next to this element. Special considerations: - * 1. The left and right bevels may not be visible if horizontal - * scrolling is enabled (the "left" and "right" variables - * are zero to indicate that the corresponding bevel is - * visible). - * 2. Top and bottom bevels are only drawn if this is the - * first or last seleted item. - * 3. If the left or right bevel isn't visible, then the "left" - * and "right" variables, computed above, have non-zero values - * that extend the top and bottom bevels so that the mitered - * corners are off-screen. - */ - - if (left == 0) { - Tk_3DVerticalBevel(tkwin, pixmap, listPtr->selBorder, - x, y, listPtr->selBorderWidth, listPtr->lineHeight, - 1, TK_RELIEF_RAISED); - } - if (right == 0) { - Tk_3DVerticalBevel(tkwin, pixmap, listPtr->selBorder, - x + width - listPtr->selBorderWidth, y, - listPtr->selBorderWidth, listPtr->lineHeight, - 0, TK_RELIEF_RAISED); - } - if (!prevSelected) { - Tk_3DHorizontalBevel(tkwin, pixmap, listPtr->selBorder, - x-left, y, width+left+right, listPtr->selBorderWidth, - 1, 1, 1, TK_RELIEF_RAISED); - } - if ((elPtr->nextPtr == NULL) || !elPtr->nextPtr->selected) { - Tk_3DHorizontalBevel(tkwin, pixmap, listPtr->selBorder, x-left, - y + listPtr->lineHeight - listPtr->selBorderWidth, - width+left+right, listPtr->selBorderWidth, 0, 0, 0, - TK_RELIEF_RAISED); - } - } - Tk_GetFontMetrics(listPtr->tkfont, &fm); - y += fm.ascent + listPtr->selBorderWidth; - x = listPtr->inset + listPtr->selBorderWidth - elPtr->lBearing - - listPtr->xOffset; - Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont, - elPtr->text, elPtr->textLength, x, y); - - /* - * If this is the active element, underline it. - */ - - if ((i == listPtr->active) && (listPtr->flags & GOT_FOCUS)) { - Tk_UnderlineChars(listPtr->display, pixmap, gc, listPtr->tkfont, - elPtr->text, x, y, 0, elPtr->textLength); - } - } - - /* - * Redraw the border for the listbox to make sure that it's on top - * of any of the text of the listbox entries. - */ - - Tk_Draw3DRectangle(tkwin, pixmap, listPtr->normalBorder, - listPtr->highlightWidth, listPtr->highlightWidth, - Tk_Width(tkwin) - 2*listPtr->highlightWidth, - Tk_Height(tkwin) - 2*listPtr->highlightWidth, - listPtr->borderWidth, listPtr->relief); - if (listPtr->highlightWidth > 0) { - GC gc; - - if (listPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(listPtr->highlightColorPtr, pixmap); - } else { - gc = Tk_GCForColor(listPtr->highlightBgColorPtr, pixmap); - } - Tk_DrawFocusHighlight(tkwin, gc, listPtr->highlightWidth, pixmap); - } - XCopyArea(listPtr->display, pixmap, Tk_WindowId(tkwin), - listPtr->textGC, 0, 0, (unsigned) Tk_Width(tkwin), - (unsigned) Tk_Height(tkwin), 0, 0); - Tk_FreePixmap(listPtr->display, pixmap); -} - -/* - *---------------------------------------------------------------------- - * - * ListboxComputeGeometry -- - * - * This procedure is invoked to recompute geometry information - * such as the sizes of the elements and the overall dimensions - * desired for the listbox. - * - * Results: - * None. - * - * Side effects: - * Geometry information is updated and a new requested size is - * registered for the widget. Internal border and gridding - * information is also set. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxComputeGeometry(listPtr, fontChanged, maxIsStale, updateGrid) - Listbox *listPtr; /* Listbox whose geometry is to be - * recomputed. */ - int fontChanged; /* Non-zero means the font may have changed - * so per-element width information also - * has to be computed. */ - int maxIsStale; /* Non-zero means the "maxWidth" field may - * no longer be up-to-date and must - * be recomputed. If fontChanged is 1 then - * this must be 1. */ - int updateGrid; /* Non-zero means call Tk_SetGrid or - * Tk_UnsetGrid to update gridding for - * the window. */ -{ - register Element *elPtr; - int width, height, pixelWidth, pixelHeight; - Tk_FontMetrics fm; - - if (fontChanged || maxIsStale) { - listPtr->xScrollUnit = Tk_TextWidth(listPtr->tkfont, "0", 1); - if (listPtr->xScrollUnit == 0) { - listPtr->xScrollUnit = 1; - } - listPtr->maxWidth = 0; - for (elPtr = listPtr->firstPtr; elPtr != NULL; elPtr = elPtr->nextPtr) { - if (fontChanged) { - elPtr->pixelWidth = Tk_TextWidth(listPtr->tkfont, - elPtr->text, elPtr->textLength); - elPtr->lBearing = 0; - } - if (elPtr->pixelWidth > listPtr->maxWidth) { - listPtr->maxWidth = elPtr->pixelWidth; - } - } - } - - Tk_GetFontMetrics(listPtr->tkfont, &fm); - listPtr->lineHeight = fm.linespace + 1 + 2*listPtr->selBorderWidth; - width = listPtr->width; - if (width <= 0) { - width = (listPtr->maxWidth + listPtr->xScrollUnit - 1) - /listPtr->xScrollUnit; - if (width < 1) { - width = 1; - } - } - pixelWidth = width*listPtr->xScrollUnit + 2*listPtr->inset - + 2*listPtr->selBorderWidth; - height = listPtr->height; - if (listPtr->height <= 0) { - height = listPtr->numElements; - if (height < 1) { - height = 1; - } - } - pixelHeight = height*listPtr->lineHeight + 2*listPtr->inset; - Tk_GeometryRequest(listPtr->tkwin, pixelWidth, pixelHeight); - Tk_SetInternalBorder(listPtr->tkwin, listPtr->inset); - if (updateGrid) { - if (listPtr->setGrid) { - Tk_SetGrid(listPtr->tkwin, width, height, listPtr->xScrollUnit, - listPtr->lineHeight); - } else { - Tk_UnsetGrid(listPtr->tkwin); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * InsertEls -- - * - * Add new elements to a listbox widget. - * - * Results: - * None. - * - * Side effects: - * New information gets added to listPtr; it will be redisplayed - * soon, but not immediately. - * - *---------------------------------------------------------------------- - */ - -static void -InsertEls(listPtr, index, argc, argv) - register Listbox *listPtr; /* Listbox that is to get the new - * elements. */ - int index; /* Add the new elements before this - * element. */ - int argc; /* Number of new elements to add. */ - char **argv; /* New elements (one per entry). */ -{ - register Element *prevPtr, *newPtr; - int length, i, oldMaxWidth; - - /* - * Find the element before which the new ones will be inserted. - */ - - if (index <= 0) { - index = 0; - } - if (index > listPtr->numElements) { - index = listPtr->numElements; - } - if (index == 0) { - prevPtr = NULL; - } else if (index == listPtr->numElements) { - prevPtr = listPtr->lastPtr; - } else { - for (prevPtr = listPtr->firstPtr, i = index - 1; i > 0; i--) { - prevPtr = prevPtr->nextPtr; - } - } - - /* - * For each new element, create a record, initialize it, and link - * it into the list of elements. - */ - - oldMaxWidth = listPtr->maxWidth; - for (i = argc ; i > 0; i--, argv++, prevPtr = newPtr) { - length = strlen(*argv); - newPtr = (Element *) ckalloc(ElementSize(length)); - newPtr->textLength = length; - strcpy(newPtr->text, *argv); - newPtr->pixelWidth = Tk_TextWidth(listPtr->tkfont, newPtr->text, - newPtr->textLength); - newPtr->lBearing = 0; - if (newPtr->pixelWidth > listPtr->maxWidth) { - listPtr->maxWidth = newPtr->pixelWidth; - } - newPtr->selected = 0; - if (prevPtr == NULL) { - newPtr->nextPtr = listPtr->firstPtr; - listPtr->firstPtr = newPtr; - } else { - newPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = newPtr; - } - } - if ((prevPtr != NULL) && (prevPtr->nextPtr == NULL)) { - listPtr->lastPtr = prevPtr; - } - listPtr->numElements += argc; - - /* - * Update the selection and other indexes to account for the - * renumbering that has just occurred. Then arrange for the new - * information to be displayed. - */ - - if (index <= listPtr->selectAnchor) { - listPtr->selectAnchor += argc; - } - if (index < listPtr->topIndex) { - listPtr->topIndex += argc; - } - if (index <= listPtr->active) { - listPtr->active += argc; - if ((listPtr->active >= listPtr->numElements) - && (listPtr->numElements > 0)) { - listPtr->active = listPtr->numElements-1; - } - } - listPtr->flags |= UPDATE_V_SCROLLBAR; - if (listPtr->maxWidth != oldMaxWidth) { - listPtr->flags |= UPDATE_H_SCROLLBAR; - } - ListboxComputeGeometry(listPtr, 0, 0, 0); - ListboxRedrawRange(listPtr, index, listPtr->numElements-1); -} - -/* - *---------------------------------------------------------------------- - * - * DeleteEls -- - * - * Remove one or more elements from a listbox widget. - * - * Results: - * None. - * - * Side effects: - * Memory gets freed, the listbox gets modified and (eventually) - * redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteEls(listPtr, first, last) - register Listbox *listPtr; /* Listbox widget to modify. */ - int first; /* Index of first element to delete. */ - int last; /* Index of last element to delete. */ -{ - register Element *prevPtr, *elPtr; - int count, i, widthChanged; - - /* - * Adjust the range to fit within the existing elements of the - * listbox, and make sure there's something to delete. - */ - - if (first < 0) { - first = 0; - } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; - } - count = last + 1 - first; - if (count <= 0) { - return; - } - - /* - * Find the element just before the ones to delete. - */ - - if (first == 0) { - prevPtr = NULL; - } else { - for (i = first-1, prevPtr = listPtr->firstPtr; i > 0; i--) { - prevPtr = prevPtr->nextPtr; - } - } - - /* - * Delete the requested number of elements. - */ - - widthChanged = 0; - for (i = count; i > 0; i--) { - if (prevPtr == NULL) { - elPtr = listPtr->firstPtr; - listPtr->firstPtr = elPtr->nextPtr; - if (listPtr->firstPtr == NULL) { - listPtr->lastPtr = NULL; - } - } else { - elPtr = prevPtr->nextPtr; - prevPtr->nextPtr = elPtr->nextPtr; - if (prevPtr->nextPtr == NULL) { - listPtr->lastPtr = prevPtr; - } - } - if (elPtr->pixelWidth == listPtr->maxWidth) { - widthChanged = 1; - } - if (elPtr->selected) { - listPtr->numSelected -= 1; - } - ckfree((char *) elPtr); - } - listPtr->numElements -= count; - - /* - * Update the selection and viewing information to reflect the change - * in the element numbering, and redisplay to slide information up over - * the elements that were deleted. - */ - - if (first <= listPtr->selectAnchor) { - listPtr->selectAnchor -= count; - if (listPtr->selectAnchor < first) { - listPtr->selectAnchor = first; - } - } - if (first <= listPtr->topIndex) { - listPtr->topIndex -= count; - if (listPtr->topIndex < first) { - listPtr->topIndex = first; - } - } - if (listPtr->topIndex > (listPtr->numElements - listPtr->fullLines)) { - listPtr->topIndex = listPtr->numElements - listPtr->fullLines; - if (listPtr->topIndex < 0) { - listPtr->topIndex = 0; - } - } - if (listPtr->active > last) { - listPtr->active -= count; - } else if (listPtr->active >= first) { - listPtr->active = first; - if ((listPtr->active >= listPtr->numElements) - && (listPtr->numElements > 0)) { - listPtr->active = listPtr->numElements-1; - } - } - listPtr->flags |= UPDATE_V_SCROLLBAR; - ListboxComputeGeometry(listPtr, 0, widthChanged, 0); - if (widthChanged) { - listPtr->flags |= UPDATE_H_SCROLLBAR; - } - ListboxRedrawRange(listPtr, first, listPtr->numElements-1); -} - -/* - *-------------------------------------------------------------- - * - * ListboxEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on listboxes. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -ListboxEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - Listbox *listPtr = (Listbox *) clientData; - - if (eventPtr->type == Expose) { - ListboxRedrawRange(listPtr, - NearestListboxElement(listPtr, eventPtr->xexpose.y), - NearestListboxElement(listPtr, eventPtr->xexpose.y - + eventPtr->xexpose.height)); - } else if (eventPtr->type == DestroyNotify) { - if (listPtr->tkwin != NULL) { - if (listPtr->setGrid) { - Tk_UnsetGrid(listPtr->tkwin); - } - listPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(listPtr->interp, listPtr->widgetCmd); - } - if (listPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayListbox, (ClientData) listPtr); - } - Tcl_EventuallyFree((ClientData) listPtr, DestroyListbox); - } else if (eventPtr->type == ConfigureNotify) { - int vertSpace; - - vertSpace = Tk_Height(listPtr->tkwin) - 2*listPtr->inset; - listPtr->fullLines = vertSpace / listPtr->lineHeight; - if ((listPtr->fullLines*listPtr->lineHeight) < vertSpace) { - listPtr->partialLine = 1; - } else { - listPtr->partialLine = 0; - } - listPtr->flags |= UPDATE_V_SCROLLBAR|UPDATE_H_SCROLLBAR; - ChangeListboxView(listPtr, listPtr->topIndex); - ChangeListboxOffset(listPtr, listPtr->xOffset); - - /* - * Redraw the whole listbox. It's hard to tell what needs - * to be redrawn (e.g. if the listbox has shrunk then we - * may only need to redraw the borders), so just redraw - * everything for safety. - */ - - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - listPtr->flags |= GOT_FOCUS; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - listPtr->flags &= ~GOT_FOCUS; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ListboxCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - Listbox *listPtr = (Listbox *) clientData; - Tk_Window tkwin = listPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - if (listPtr->setGrid) { - Tk_UnsetGrid(listPtr->tkwin); - } - listPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * GetListboxIndex -- - * - * Parse an index into a listbox and return either its value - * or an error. - * - * Results: - * A standard Tcl result. If all went well, then *indexPtr is - * filled in with the index (into listPtr) corresponding to - * string. Otherwise an error message is left in interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -GetListboxIndex(interp, listPtr, string, endIsSize, indexPtr) - Tcl_Interp *interp; /* For error messages. */ - Listbox *listPtr; /* Listbox for which the index is being - * specified. */ - char *string; /* Specifies an element in the listbox. */ - int endIsSize; /* If 1, "end" refers to the number of - * entries in the listbox. If 0, "end" - * refers to 1 less than the number of - * entries. */ - int *indexPtr; /* Where to store converted index. */ -{ - int c; - size_t length; - - length = strlen(string); - c = string[0]; - if ((c == 'a') && (strncmp(string, "active", length) == 0) - && (length >= 2)) { - *indexPtr = listPtr->active; - } else if ((c == 'a') && (strncmp(string, "anchor", length) == 0) - && (length >= 2)) { - *indexPtr = listPtr->selectAnchor; - } else if ((c == 'e') && (strncmp(string, "end", length) == 0)) { - if (endIsSize) { - *indexPtr = listPtr->numElements; - } else { - *indexPtr = listPtr->numElements - 1; - } - } else if (c == '@') { - int y; - char *p, *end; - - p = string+1; - strtol(p, &end, 0); - if ((end == p) || (*end != ',')) { - goto badIndex; - } - p = end+1; - y = strtol(p, &end, 0); - if ((end == p) || (*end != 0)) { - goto badIndex; - } - *indexPtr = NearestListboxElement(listPtr, y); - } else { - if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) { - Tcl_ResetResult(interp); - goto badIndex; - } - } - return TCL_OK; - - badIndex: - Tcl_AppendResult(interp, "bad listbox index \"", string, - "\": must be active, anchor, end, @x,y, or a number", - (char *) NULL); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * ChangeListboxView -- - * - * Change the view on a listbox widget so that a given element - * is displayed at the top. - * - * Results: - * None. - * - * Side effects: - * What's displayed on the screen is changed. If there is a - * scrollbar associated with this widget, then the scrollbar - * is instructed to change its display too. - * - *---------------------------------------------------------------------- - */ - -static void -ChangeListboxView(listPtr, index) - register Listbox *listPtr; /* Information about widget. */ - int index; /* Index of element in listPtr - * that should now appear at the - * top of the listbox. */ -{ - if (index >= (listPtr->numElements - listPtr->fullLines)) { - index = listPtr->numElements - listPtr->fullLines; - } - if (index < 0) { - index = 0; - } - if (listPtr->topIndex != index) { - listPtr->topIndex = index; - if (!(listPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayListbox, (ClientData) listPtr); - listPtr->flags |= REDRAW_PENDING; - } - listPtr->flags |= UPDATE_V_SCROLLBAR; - } -} - -/* - *---------------------------------------------------------------------- - * - * ChangListboxOffset -- - * - * Change the horizontal offset for a listbox. - * - * Results: - * None. - * - * Side effects: - * The listbox may be redrawn to reflect its new horizontal - * offset. - * - *---------------------------------------------------------------------- - */ - -static void -ChangeListboxOffset(listPtr, offset) - register Listbox *listPtr; /* Information about widget. */ - int offset; /* Desired new "xOffset" for - * listbox. */ -{ - int maxOffset; - - /* - * Make sure that the new offset is within the allowable range, and - * round it off to an even multiple of xScrollUnit. - */ - - maxOffset = listPtr->maxWidth - (Tk_Width(listPtr->tkwin) - - 2*listPtr->inset - 2*listPtr->selBorderWidth) - + listPtr->xScrollUnit - 1; - if (offset > maxOffset) { - offset = maxOffset; - } - if (offset < 0) { - offset = 0; - } - offset -= offset % listPtr->xScrollUnit; - if (offset != listPtr->xOffset) { - listPtr->xOffset = offset; - listPtr->flags |= UPDATE_H_SCROLLBAR; - ListboxRedrawRange(listPtr, 0, listPtr->numElements); - } -} - -/* - *---------------------------------------------------------------------- - * - * ListboxScanTo -- - * - * Given a point (presumably of the curent mouse location) - * drag the view in the window to implement the scan operation. - * - * Results: - * None. - * - * Side effects: - * The view in the window may change. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxScanTo(listPtr, x, y) - register Listbox *listPtr; /* Information about widget. */ - int x; /* X-coordinate to use for scan - * operation. */ - int y; /* Y-coordinate to use for scan - * operation. */ -{ - int newTopIndex, newOffset, maxIndex, maxOffset; - - maxIndex = listPtr->numElements - listPtr->fullLines; - maxOffset = listPtr->maxWidth + (listPtr->xScrollUnit - 1) - - (Tk_Width(listPtr->tkwin) - 2*listPtr->inset - - 2*listPtr->selBorderWidth - listPtr->xScrollUnit); - - /* - * Compute new top line for screen by amplifying the difference - * between the current position and the place where the scan - * started (the "mark" position). If we run off the top or bottom - * of the list, then reset the mark point so that the current - * position continues to correspond to the edge of the window. - * This means that the picture will start dragging as soon as the - * mouse reverses direction (without this reset, might have to slide - * mouse a long ways back before the picture starts moving again). - */ - - newTopIndex = listPtr->scanMarkYIndex - - (10*(y - listPtr->scanMarkY))/listPtr->lineHeight; - if (newTopIndex > maxIndex) { - newTopIndex = listPtr->scanMarkYIndex = maxIndex; - listPtr->scanMarkY = y; - } else if (newTopIndex < 0) { - newTopIndex = listPtr->scanMarkYIndex = 0; - listPtr->scanMarkY = y; - } - ChangeListboxView(listPtr, newTopIndex); - - /* - * Compute new left edge for display in a similar fashion by amplifying - * the difference between the current position and the place where the - * scan started. - */ - - newOffset = listPtr->scanMarkXOffset - (10*(x - listPtr->scanMarkX)); - if (newOffset > maxOffset) { - newOffset = listPtr->scanMarkXOffset = maxOffset; - listPtr->scanMarkX = x; - } else if (newOffset < 0) { - newOffset = listPtr->scanMarkXOffset = 0; - listPtr->scanMarkX = x; - } - ChangeListboxOffset(listPtr, newOffset); -} - -/* - *---------------------------------------------------------------------- - * - * NearestListboxElement -- - * - * Given a y-coordinate inside a listbox, compute the index of - * the element under that y-coordinate (or closest to that - * y-coordinate). - * - * Results: - * The return value is an index of an element of listPtr. If - * listPtr has no elements, then 0 is always returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -NearestListboxElement(listPtr, y) - register Listbox *listPtr; /* Information about widget. */ - int y; /* Y-coordinate in listPtr's window. */ -{ - int index; - - index = (y - listPtr->inset)/listPtr->lineHeight; - if (index >= (listPtr->fullLines + listPtr->partialLine)) { - index = listPtr->fullLines + listPtr->partialLine - 1; - } - if (index < 0) { - index = 0; - } - index += listPtr->topIndex; - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; - } - return index; -} - -/* - *---------------------------------------------------------------------- - * - * ListboxSelect -- - * - * Select or deselect one or more elements in a listbox.. - * - * Results: - * None. - * - * Side effects: - * All of the elements in the range between first and last are - * marked as either selected or deselected, depending on the - * "select" argument. Any items whose state changes are redisplayed. - * The selection is claimed from X when the number of selected - * elements changes from zero to non-zero. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxSelect(listPtr, first, last, select) - register Listbox *listPtr; /* Information about widget. */ - int first; /* Index of first element to - * select or deselect. */ - int last; /* Index of last element to - * select or deselect. */ - int select; /* 1 means select items, 0 means - * deselect them. */ -{ - int i, firstRedisplay, increment, oldCount; - Element *elPtr; - - if (last < first) { - i = first; - first = last; - last = i; - } - if ((last < 0) || (first >= listPtr->numElements)) { - return; - } - if (first < 0) { - first = 0; - } - if (last >= listPtr->numElements) { - last = listPtr->numElements - 1; - } - oldCount = listPtr->numSelected; - firstRedisplay = -1; - increment = select ? 1 : -1; - for (i = 0, elPtr = listPtr->firstPtr; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - for ( ; i <= last; i++, elPtr = elPtr->nextPtr) { - if (elPtr->selected == select) { - continue; - } - listPtr->numSelected += increment; - elPtr->selected = select; - if (firstRedisplay < 0) { - firstRedisplay = i; - } - } - if (firstRedisplay >= 0) { - ListboxRedrawRange(listPtr, first, last); - } - if ((oldCount == 0) && (listPtr->numSelected > 0) - && (listPtr->exportSelection)) { - Tk_OwnSelection(listPtr->tkwin, XA_PRIMARY, ListboxLostSelection, - (ClientData) listPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * ListboxFetchSelection -- - * - * This procedure is called back by Tk when the selection is - * requested by someone. It returns part or all of the selection - * in a buffer provided by the caller. - * - * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. The selection is returned - * as a Tcl list with one list element for each element in the - * listbox. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ListboxFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about listbox widget. */ - int offset; /* Offset within selection of first - * byte to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ -{ - register Listbox *listPtr = (Listbox *) clientData; - register Element *elPtr; - Tcl_DString selection; - int length, count, needNewline; - - if (!listPtr->exportSelection) { - return -1; - } - - /* - * Use a dynamic string to accumulate the contents of the selection. - */ - - needNewline = 0; - Tcl_DStringInit(&selection); - for (elPtr = listPtr->firstPtr; elPtr != NULL; elPtr = elPtr->nextPtr) { - if (elPtr->selected) { - if (needNewline) { - Tcl_DStringAppend(&selection, "\n", 1); - } - Tcl_DStringAppend(&selection, elPtr->text, elPtr->textLength); - needNewline = 1; - } - } - - length = Tcl_DStringLength(&selection); - if (length == 0) { - return -1; - } - - /* - * Copy the requested portion of the selection to the buffer. - */ - - count = length - offset; - if (count <= 0) { - count = 0; - } else { - if (count > maxBytes) { - count = maxBytes; - } - memcpy((VOID *) buffer, - (VOID *) (Tcl_DStringValue(&selection) + offset), - (size_t) count); - } - buffer[count] = '\0'; - Tcl_DStringFree(&selection); - return count; -} - -/* - *---------------------------------------------------------------------- - * - * ListboxLostSelection -- - * - * This procedure is called back by Tk when the selection is - * grabbed away from a listbox widget. - * - * Results: - * None. - * - * Side effects: - * The existing selection is unhighlighted, and the window is - * marked as not containing a selection. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxLostSelection(clientData) - ClientData clientData; /* Information about listbox widget. */ -{ - register Listbox *listPtr = (Listbox *) clientData; - - if ((listPtr->exportSelection) && (listPtr->numElements > 0)) { - ListboxSelect(listPtr, 0, listPtr->numElements-1, 0); - } -} - -/* - *---------------------------------------------------------------------- - * - * ListboxRedrawRange -- - * - * Ensure that a given range of elements is eventually redrawn on - * the display (if those elements in fact appear on the display). - * - * Results: - * None. - * - * Side effects: - * Information gets redisplayed. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ListboxRedrawRange(listPtr, first, last) - register Listbox *listPtr; /* Information about widget. */ - int first; /* Index of first element in list - * that needs to be redrawn. */ - int last; /* Index of last element in list - * that needs to be redrawn. May - * be less than first; - * these just bracket a range. */ -{ - if ((listPtr->tkwin == NULL) || !Tk_IsMapped(listPtr->tkwin) - || (listPtr->flags & REDRAW_PENDING)) { - return; - } - Tcl_DoWhenIdle(DisplayListbox, (ClientData) listPtr); - listPtr->flags |= REDRAW_PENDING; -} - -/* - *---------------------------------------------------------------------- - * - * ListboxUpdateVScrollbar -- - * - * This procedure is invoked whenever information has changed in - * a listbox in a way that would invalidate a vertical scrollbar - * display. If there is an associated scrollbar, then this command - * updates it by invoking a Tcl command. - * - * Results: - * None. - * - * Side effects: - * A Tcl command is invoked, and an additional command may be - * invoked to process errors in the command. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxUpdateVScrollbar(listPtr) - register Listbox *listPtr; /* Information about widget. */ -{ - char string[100]; - double first, last; - int result; - Tcl_Interp *interp; - - if (listPtr->yScrollCmd == NULL) { - return; - } - if (listPtr->numElements == 0) { - first = 0.0; - last = 1.0; - } else { - first = listPtr->topIndex/((double) listPtr->numElements); - last = (listPtr->topIndex+listPtr->fullLines) - /((double) listPtr->numElements); - if (last > 1.0) { - last = 1.0; - } - } - sprintf(string, " %g %g", first, last); - - /* - * We must hold onto the interpreter from the listPtr because the data - * at listPtr might be freed as a result of the Tcl_VarEval. - */ - - interp = listPtr->interp; - Tcl_Preserve((ClientData) interp); - result = Tcl_VarEval(interp, listPtr->yScrollCmd, string, - (char *) NULL); - if (result != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (vertical scrolling command executed by listbox)"); - Tcl_BackgroundError(interp); - } - Tcl_Release((ClientData) interp); -} - -/* - *---------------------------------------------------------------------- - * - * ListboxUpdateHScrollbar -- - * - * This procedure is invoked whenever information has changed in - * a listbox in a way that would invalidate a horizontal scrollbar - * display. If there is an associated horizontal scrollbar, then - * this command updates it by invoking a Tcl command. - * - * Results: - * None. - * - * Side effects: - * A Tcl command is invoked, and an additional command may be - * invoked to process errors in the command. - * - *---------------------------------------------------------------------- - */ - -static void -ListboxUpdateHScrollbar(listPtr) - register Listbox *listPtr; /* Information about widget. */ -{ - char string[60]; - int result, windowWidth; - double first, last; - Tcl_Interp *interp; - - if (listPtr->xScrollCmd == NULL) { - return; - } - windowWidth = Tk_Width(listPtr->tkwin) - 2*(listPtr->inset - + listPtr->selBorderWidth); - if (listPtr->maxWidth == 0) { - first = 0; - last = 1.0; - } else { - first = listPtr->xOffset/((double) listPtr->maxWidth); - last = (listPtr->xOffset + windowWidth) - /((double) listPtr->maxWidth); - if (last > 1.0) { - last = 1.0; - } - } - sprintf(string, " %g %g", first, last); - - /* - * We must hold onto the interpreter because the data referred to at - * listPtr might be freed as a result of the call to Tcl_VarEval. - */ - - interp = listPtr->interp; - Tcl_Preserve((ClientData) interp); - result = Tcl_VarEval(interp, listPtr->xScrollCmd, string, - (char *) NULL); - if (result != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (horizontal scrolling command executed by listbox)"); - Tcl_BackgroundError(interp); - } - Tcl_Release((ClientData) interp); -} diff --git a/generic/tkMacWinMenu.c b/generic/tkMacWinMenu.c deleted file mode 100644 index 6453a5f..0000000 --- a/generic/tkMacWinMenu.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * tkMacWinMenu.c -- - * - * This module implements the common elements of the Mac and Windows - * specific features of menus. This file is not used for UNIX. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMacWinMenu.c,v 1.2 1998/09/14 18:23:14 stanton Exp $ - */ - -#include "tkMenu.h" - -static int postCommandGeneration; - -static int PreprocessMenu _ANSI_ARGS_((TkMenu *menuPtr)); - - -/* - *---------------------------------------------------------------------- - * - * PreprocessMenu -- - * - * The guts of the preprocessing. Recursive. - * - * Results: - * The return value is a standard Tcl result (errors can occur - * while the postcommands are being processed). - * - * Side effects: - * Since commands can get executed while this routine is being executed, - * the entire world can change. - * - *---------------------------------------------------------------------- - */ - -static int -PreprocessMenu(menuPtr) - TkMenu *menuPtr; -{ - int index, result, finished; - TkMenu *cascadeMenuPtr; - - Tcl_Preserve((ClientData) menuPtr); - - /* - * First, let's process the post command on ourselves. If this command - * destroys this menu, or if there was an error, we are done. - */ - - result = TkPostCommand(menuPtr); - if ((result != TCL_OK) || (menuPtr->tkwin == NULL)) { - goto done; - } - - /* - * Now, we go through structure and process all of the commands. - * Since the structure is changing, we stop after we do one command, - * and start over. When we get through without doing any, we are done. - */ - - - do { - finished = 1; - for (index = 0; index < menuPtr->numEntries; index++) { - if ((menuPtr->entries[index]->type == CASCADE_ENTRY) - && (menuPtr->entries[index]->name != NULL)) { - if ((menuPtr->entries[index]->childMenuRefPtr != NULL) - && (menuPtr->entries[index]->childMenuRefPtr->menuPtr - != NULL)) { - cascadeMenuPtr = - menuPtr->entries[index]->childMenuRefPtr->menuPtr; - if (cascadeMenuPtr->postCommandGeneration != - postCommandGeneration) { - cascadeMenuPtr->postCommandGeneration = - postCommandGeneration; - result = PreprocessMenu(cascadeMenuPtr); - if (result != TCL_OK) { - goto done; - } - finished = 0; - break; - } - } - } - } - } while (!finished); - - done: - Tcl_Release((ClientData)menuPtr); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * TkPreprocessMenu -- - * - * On the Mac and on Windows, all of the postcommand processing has - * to be done on the entire tree underneath the main window to be - * posted. This means that we have to traverse the menu tree and - * issue the postcommands for all of the menus that have cascades - * attached. Since the postcommands can change the menu structure while - * we are traversing, we have to be extremely careful. Basically, the - * idea is to traverse the structure until we succesfully process - * one postcommand. Then we start over, and do it again until - * we traverse the whole structure without processing any postcommands. - * - * We are also going to set up the cascade back pointers in here - * since we have to traverse the entire structure underneath the menu - * anyway, We can clear the postcommand marks while we do that. - * - * Results: - * The return value is a standard Tcl result (errors can occur - * while the postcommands are being processed). - * - * Side effects: - * Since commands can get executed while this routine is being executed, - * the entire world can change. - * - *---------------------------------------------------------------------- - */ - -int -TkPreprocessMenu(menuPtr) - TkMenu *menuPtr; -{ - postCommandGeneration++; - menuPtr->postCommandGeneration = postCommandGeneration; - return PreprocessMenu(menuPtr); -} diff --git a/generic/tkMain.c b/generic/tkMain.c deleted file mode 100644 index 0583408..0000000 --- a/generic/tkMain.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * tkMain.c -- - * - * This file contains a generic main program for Tk-based applications. - * It can be used as-is for many applications, just by supplying a - * different appInitProc procedure for each specific application. - * Or, it can be used as a template for creating new main programs - * for Tk applications. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMain.c,v 1.2 1998/09/14 18:23:14 stanton Exp $ - */ - -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <tcl.h> -#include <tk.h> -#ifdef NO_STDLIB_H -# include "../compat/stdlib.h" -#else -# include <stdlib.h> -#endif - -/* - * Declarations for various library procedures and variables (don't want - * to include tkInt.h or tkPort.h here, because people might copy this - * file out of the Tk source directory to make their own modified versions). - * Note: don't declare "exit" here even though a declaration is really - * needed, because it will conflict with a declaration elsewhere on - * some systems. - */ - -extern int isatty _ANSI_ARGS_((int fd)); -#if !defined(__WIN32__) && !defined(_WIN32) -extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); -#endif -extern void TkpDisplayWarning _ANSI_ARGS_((char *msg, - char *title)); - -/* - * Global variables used by the main program: - */ - -static Tcl_Interp *interp; /* Interpreter for this application. */ -static Tcl_DString command; /* Used to assemble lines of terminal input - * into Tcl commands. */ -static Tcl_DString line; /* Used to read the next line from the - * terminal input. */ -static int tty; /* Non-zero means standard input is a - * terminal-like device. Zero means it's - * a file. */ - -/* - * Forward declarations for procedures defined later in this file. - */ - -static void Prompt _ANSI_ARGS_((Tcl_Interp *interp, int partial)); -static void StdinProc _ANSI_ARGS_((ClientData clientData, - int mask)); - -/* - *---------------------------------------------------------------------- - * - * Tk_Main -- - * - * Main program for Wish and most other Tk-based applications. - * - * Results: - * None. This procedure never returns (it exits the process when - * it's done. - * - * Side effects: - * This procedure initializes the Tk world and then starts - * interpreting commands; almost anything could happen, depending - * on the script being interpreted. - * - *---------------------------------------------------------------------- - */ - -void -Tk_Main(argc, argv, appInitProc) - int argc; /* Number of arguments. */ - char **argv; /* Array of argument strings. */ - Tcl_AppInitProc *appInitProc; /* Application-specific initialization - * procedure to call after most - * initialization but before starting - * to execute commands. */ -{ - char *args, *fileName; - char buf[20]; - int code; - size_t length; - Tcl_Channel inChannel, outChannel; - - Tcl_FindExecutable(argv[0]); - interp = Tcl_CreateInterp(); -#ifdef TCL_MEM_DEBUG - Tcl_InitMemory(interp); -#endif - - /* - * Parse command-line arguments. A leading "-file" argument is - * ignored (a historical relic from the distant past). If the - * next argument doesn't start with a "-" then strip it off and - * use it as the name of a script file to process. - */ - - fileName = NULL; - if (argc > 1) { - length = strlen(argv[1]); - if ((length >= 2) && (strncmp(argv[1], "-file", length) == 0)) { - argc--; - argv++; - } - } - if ((argc > 1) && (argv[1][0] != '-')) { - fileName = argv[1]; - argc--; - argv++; - } - - /* - * Make command-line arguments available in the Tcl variables "argc" - * and "argv". - */ - - args = Tcl_Merge(argc-1, argv+1); - Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY); - ckfree(args); - sprintf(buf, "%d", argc-1); - Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0], - TCL_GLOBAL_ONLY); - - /* - * Set the "tcl_interactive" variable. - */ - - /* - * For now, under Windows, we assume we are not running as a console mode - * app, so we need to use the GUI console. In order to enable this, we - * always claim to be running on a tty. This probably isn't the right - * way to do it. - */ - -#ifdef __WIN32__ - tty = 1; -#else - tty = isatty(0); -#endif - Tcl_SetVar(interp, "tcl_interactive", - ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY); - - /* - * Invoke application-specific initialization. - */ - - if ((*appInitProc)(interp) != TCL_OK) { - TkpDisplayWarning(interp->result, "Application initialization failed"); - } - - /* - * Invoke the script specified on the command line, if any. - */ - - if (fileName != NULL) { - code = Tcl_EvalFile(interp, fileName); - if (code != TCL_OK) { - /* - * The following statement guarantees that the errorInfo - * variable is set properly. - */ - - Tcl_AddErrorInfo(interp, ""); - TkpDisplayWarning(Tcl_GetVar(interp, "errorInfo", - TCL_GLOBAL_ONLY), "Error in startup script"); - Tcl_DeleteInterp(interp); - Tcl_Exit(1); - } - tty = 0; - } else { - - /* - * Evaluate the .rc file, if one has been specified. - */ - - Tcl_SourceRCFile(interp); - - /* - * Establish a channel handler for stdin. - */ - - inChannel = Tcl_GetStdChannel(TCL_STDIN); - if (inChannel) { - Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc, - (ClientData) inChannel); - } - if (tty) { - Prompt(interp, 0); - } - } - - outChannel = Tcl_GetStdChannel(TCL_STDOUT); - if (outChannel) { - Tcl_Flush(outChannel); - } - Tcl_DStringInit(&command); - Tcl_DStringInit(&line); - Tcl_ResetResult(interp); - - /* - * Loop infinitely, waiting for commands to execute. When there - * are no windows left, Tk_MainLoop returns and we exit. - */ - - Tk_MainLoop(); - Tcl_DeleteInterp(interp); - Tcl_Exit(0); -} - -/* - *---------------------------------------------------------------------- - * - * StdinProc -- - * - * This procedure is invoked by the event dispatcher whenever - * standard input becomes readable. It grabs the next line of - * input characters, adds them to a command being assembled, and - * executes the command if it's complete. - * - * Results: - * None. - * - * Side effects: - * Could be almost arbitrary, depending on the command that's - * typed. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -StdinProc(clientData, mask) - ClientData clientData; /* Not used. */ - int mask; /* Not used. */ -{ - static int gotPartial = 0; - char *cmd; - int code, count; - Tcl_Channel chan = (Tcl_Channel) clientData; - - count = Tcl_Gets(chan, &line); - - if (count < 0) { - if (!gotPartial) { - if (tty) { - Tcl_Exit(0); - } else { - Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan); - } - return; - } - } - - (void) Tcl_DStringAppend(&command, Tcl_DStringValue(&line), -1); - cmd = Tcl_DStringAppend(&command, "\n", -1); - Tcl_DStringFree(&line); - if (!Tcl_CommandComplete(cmd)) { - gotPartial = 1; - goto prompt; - } - gotPartial = 0; - - /* - * Disable the stdin channel handler while evaluating the command; - * otherwise if the command re-enters the event loop we might - * process commands from stdin before the current command is - * finished. Among other things, this will trash the text of the - * command being evaluated. - */ - - Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) chan); - code = Tcl_RecordAndEval(interp, cmd, TCL_EVAL_GLOBAL); - - chan = Tcl_GetStdChannel(TCL_STDIN); - if (chan) { - Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc, - (ClientData) chan); - } - Tcl_DStringFree(&command); - if (*interp->result != 0) { - if ((code != TCL_OK) || (tty)) { - /* - * The statement below used to call "printf", but that resulted - * in core dumps under Solaris 2.3 if the result was very long. - * - * NOTE: This probably will not work under Windows either. - */ - - puts(interp->result); - } - } - - /* - * Output a prompt. - */ - - prompt: - if (tty) { - Prompt(interp, gotPartial); - } - Tcl_ResetResult(interp); -} - -/* - *---------------------------------------------------------------------- - * - * Prompt -- - * - * Issue a prompt on standard output, or invoke a script - * to issue the prompt. - * - * Results: - * None. - * - * Side effects: - * A prompt gets output, and a Tcl script may be evaluated - * in interp. - * - *---------------------------------------------------------------------- - */ - -static void -Prompt(interp, partial) - Tcl_Interp *interp; /* Interpreter to use for prompting. */ - int partial; /* Non-zero means there already - * exists a partial command, so use - * the secondary prompt. */ -{ - char *promptCmd; - int code; - Tcl_Channel outChannel, errChannel; - - promptCmd = Tcl_GetVar(interp, - partial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY); - if (promptCmd == NULL) { -defaultPrompt: - if (!partial) { - - /* - * We must check that outChannel is a real channel - it - * is possible that someone has transferred stdout out of - * this interpreter with "interp transfer". - */ - - outChannel = Tcl_GetChannel(interp, "stdout", NULL); - if (outChannel != (Tcl_Channel) NULL) { - Tcl_Write(outChannel, "% ", 2); - } - } - } else { - code = Tcl_Eval(interp, promptCmd); - if (code != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (script that generates prompt)"); - /* - * We must check that errChannel is a real channel - it - * is possible that someone has transferred stderr out of - * this interpreter with "interp transfer". - */ - - errChannel = Tcl_GetChannel(interp, "stderr", NULL); - if (errChannel != (Tcl_Channel) NULL) { - Tcl_Write(errChannel, interp->result, -1); - Tcl_Write(errChannel, "\n", 1); - } - goto defaultPrompt; - } - } - outChannel = Tcl_GetChannel(interp, "stdout", NULL); - if (outChannel != (Tcl_Channel) NULL) { - Tcl_Flush(outChannel); - } -} diff --git a/generic/tkMenu.c b/generic/tkMenu.c deleted file mode 100644 index cbcdcb8..0000000 --- a/generic/tkMenu.c +++ /dev/null @@ -1,3057 +0,0 @@ -/* - * tkMenu.c -- - * - * This file contains most of the code for implementing menus in Tk. It takes - * care of all of the generic (platform-independent) parts of menus, and - * is supplemented by platform-specific files. The geometry calculation - * and drawing code for menus is in the file tkMenuDraw.c - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMenu.c,v 1.2 1998/09/14 18:23:14 stanton Exp $ - */ - -/* - * Notes on implementation of menus: - * - * Menus can be used in three ways: - * - as a popup menu, either as part of a menubutton or standalone. - * - as a menubar. The menu's cascade items are arranged according to - * the specific platform to provide the user access to the menus at all - * times - * - as a tearoff palette. This is a window with the menu's items in it. - * - * The goal is to provide the Tk developer with a way to use a common - * set of menus for all of these tasks. - * - * In order to make the bindings for cascade menus work properly under Unix, - * the cascade menus' pathnames must be proper children of the menu that - * they are cascade from. So if there is a menu .m, and it has two - * cascades labelled "File" and "Edit", the cascade menus might have - * the pathnames .m.file and .m.edit. Another constraint is that the menus - * used for menubars must be children of the toplevel widget that they - * are attached to. And on the Macintosh, the platform specific menu handle - * for cascades attached to a menu bar must have a title that matches the - * label for the cascade menu. - * - * To handle all of the constraints, Tk menubars and tearoff menus are - * implemented using menu clones. Menu clones are full menus in their own - * right; they have a Tk window and pathname associated with them; they have - * a TkMenu structure and array of entries. However, they are linked with the - * original menu that they were cloned from. The reflect the attributes of - * the original, or "master", menu. So if an item is added to a menu, and - * that menu has clones, then the item must be added to all of its clones - * also. Menus are cloned when a menu is torn-off or when a menu is assigned - * as a menubar using the "-menu" option of the toplevel's pathname configure - * subcommand. When a clone is destroyed, only the clone is destroyed, but - * when the master menu is destroyed, all clones are also destroyed. This - * allows the developer to just deal with one set of menus when creating - * and destroying. - * - * Clones are rather tricky when a menu with cascade entries is cloned (such - * as a menubar). Not only does the menu have to be cloned, but each cascade - * entry's corresponding menu must also be cloned. This maintains the pathname - * parent-child hierarchy necessary for menubars and toplevels to work. - * This leads to several special cases: - * - * 1. When a new menu is created, and it is pointed to by cascade entries in - * cloned menus, the new menu has to be cloned to parallel the cascade - * structure. - * 2. When a cascade item is added to a menu that has been cloned, and the - * menu that the cascade item points to exists, that menu has to be cloned. - * 3. When the menu that a cascade entry points to is changed, the old - * cloned cascade menu has to be discarded, and the new one has to be cloned. - * - */ - -#include "tkPort.h" -#include "tkMenu.h" - -#define MENU_HASH_KEY "tkMenus" - -static int menusInitialized; /* Whether or not the hash tables, etc., have - * been setup */ - -/* - * Configuration specs for individual menu entries. If this changes, be sure - * to update code in TkpMenuInit that changes the font string entry. - */ - -Tk_ConfigSpec tkMenuEntryConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACTIVE_BG, Tk_Offset(TkMenuEntry, activeBorder), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACTIVE_FG, Tk_Offset(TkMenuEntry, activeFg), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-accelerator", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACCELERATOR, Tk_Offset(TkMenuEntry, accel), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_BG, Tk_Offset(TkMenuEntry, border), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |SEPARATOR_MASK|TEAROFF_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_BITMAP, Tk_Offset(TkMenuEntry, bitmap), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-columnbreak", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_COLUMN_BREAK, Tk_Offset(TkMenuEntry, columnBreak), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, - {TK_CONFIG_STRING, "-command", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_COMMAND, Tk_Offset(TkMenuEntry, command), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_FONT, Tk_Offset(TkMenuEntry, tkfont), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_FG, Tk_Offset(TkMenuEntry, fg), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-hidemargin", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_HIDE_MARGIN, Tk_Offset(TkMenuEntry, hideMargin), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |SEPARATOR_MASK|TEAROFF_MASK}, - {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_IMAGE, Tk_Offset(TkMenuEntry, imageString), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_INDICATOR, Tk_Offset(TkMenuEntry, indicatorOn), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-label", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_LABEL, Tk_Offset(TkMenuEntry, label), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, - {TK_CONFIG_STRING, "-menu", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_MENU, Tk_Offset(TkMenuEntry, name), - CASCADE_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-offvalue", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_OFF_VALUE, Tk_Offset(TkMenuEntry, offValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_STRING, "-onvalue", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ON_VALUE, Tk_Offset(TkMenuEntry, onValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_COLOR, "-selectcolor", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_SELECT, Tk_Offset(TkMenuEntry, indicatorFg), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-selectimage", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_SELECT_IMAGE, Tk_Offset(TkMenuEntry, selectImageString), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_STATE, Tk_Offset(TkMenuEntry, state), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TEAROFF_MASK|TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-value", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_VALUE, Tk_Offset(TkMenuEntry, onValue), - RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_CHECK_VARIABLE, Tk_Offset(TkMenuEntry, name), - CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_RADIO_VARIABLE, Tk_Offset(TkMenuEntry, name), - RADIO_BUTTON_MASK}, - {TK_CONFIG_INT, "-underline", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_UNDERLINE, Tk_Offset(TkMenuEntry, underline), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Configuration specs valid for the menu as a whole. If this changes, be sure - * to update code in TkpMenuInit that changes the font string entry. - */ - -Tk_ConfigSpec tkMenuConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENU_ACTIVE_BG_COLOR, Tk_Offset(TkMenu, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENU_ACTIVE_BG_MONO, Tk_Offset(TkMenu, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", - "BorderWidth", DEF_MENU_ACTIVE_BORDER_WIDTH, - Tk_Offset(TkMenu, activeBorderWidth), 0}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENU_ACTIVE_FG_COLOR, Tk_Offset(TkMenu, activeFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENU_ACTIVE_FG_MONO, Tk_Offset(TkMenu, activeFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENU_BG_COLOR, Tk_Offset(TkMenu, border), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENU_BG_MONO, Tk_Offset(TkMenu, border), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_MENU_BORDER_WIDTH, Tk_Offset(TkMenu, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_MENU_CURSOR, Tk_Offset(TkMenu, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENU_DISABLED_FG_COLOR, - Tk_Offset(TkMenu, disabledFg), TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENU_DISABLED_FG_MONO, - Tk_Offset(TkMenu, disabledFg), TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_MENU_FONT, Tk_Offset(TkMenu, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_MENU_FG, Tk_Offset(TkMenu, fg), 0}, - {TK_CONFIG_STRING, "-postcommand", "postCommand", "Command", - DEF_MENU_POST_COMMAND, Tk_Offset(TkMenu, postCommand), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_MENU_RELIEF, Tk_Offset(TkMenu, relief), 0}, - {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", - DEF_MENU_SELECT_COLOR, Tk_Offset(TkMenu, indicatorFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", - DEF_MENU_SELECT_MONO, Tk_Offset(TkMenu, indicatorFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_MENU_TAKE_FOCUS, Tk_Offset(TkMenu, takeFocus), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-tearoff", "tearOff", "TearOff", - DEF_MENU_TEAROFF, Tk_Offset(TkMenu, tearOff), 0}, - {TK_CONFIG_STRING, "-tearoffcommand", "tearOffCommand", "TearOffCommand", - DEF_MENU_TEAROFF_CMD, Tk_Offset(TkMenu, tearOffCommand), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-title", "title", "Title", - DEF_MENU_TITLE, Tk_Offset(TkMenu, title), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-type", "type", "Type", - DEF_MENU_TYPE, Tk_Offset(TkMenu, menuTypeName), TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for static procedures in this file: - */ - -static int CloneMenu _ANSI_ARGS_((TkMenu *menuPtr, - char *newMenuName, char *newMenuTypeString)); -static int ConfigureMenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, int argc, char **argv, - int flags)); -static int ConfigureMenuCloneEntries _ANSI_ARGS_(( - Tcl_Interp *interp, TkMenu *menuPtr, int index, - int argc, char **argv, int flags)); -static int ConfigureMenuEntry _ANSI_ARGS_((TkMenuEntry *mePtr, - int argc, char **argv, int flags)); -static void DeleteMenuCloneEntries _ANSI_ARGS_((TkMenu *menuPtr, - int first, int last)); -static void DestroyMenuHashTable _ANSI_ARGS_(( - ClientData clientData, Tcl_Interp *interp)); -static void DestroyMenuInstance _ANSI_ARGS_((TkMenu *menuPtr)); -static void DestroyMenuEntry _ANSI_ARGS_((char *memPtr)); -static int GetIndexFromCoords - _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, - char *string, int *indexPtr)); -static int MenuDoYPosition _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *arg)); -static int MenuAddOrInsert _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *indexString, int argc, - char **argv)); -static void MenuCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static TkMenuEntry * MenuNewEntry _ANSI_ARGS_((TkMenu *menuPtr, int index, - int type)); -static char * MenuVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static int MenuWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void MenuWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static void RecursivelyDeleteMenu _ANSI_ARGS_((TkMenu *menuPtr)); -static void UnhookCascadeEntry _ANSI_ARGS_((TkMenuEntry *mePtr)); - -/* - * The structure below is a list of procs that respond to certain window - * manager events. One of these includes a font change, which forces - * the geometry proc to be called. - */ - -static TkClassProcs menuClass = { - NULL, /* createProc. */ - MenuWorldChanged /* geometryProc. */ -}; - - - -/* - *-------------------------------------------------------------- - * - * Tk_MenuCmd -- - * - * This procedure is invoked to process the "menu" Tcl - * command. See the user documentation for details on - * what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_MenuCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; - register TkMenu *menuPtr; - TkMenuReferences *menuRefPtr; - int i, len; - char *arg, c; - int toplevel; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - TkMenuInit(); - - toplevel = 1; - for (i = 2; i < argc; i += 2) { - arg = argv[i]; - len = strlen(arg); - if (len < 2) { - continue; - } - c = arg[1]; - if ((c == 't') && (strncmp(arg, "-type", strlen(arg)) == 0) - && (len >= 3)) { - if (strcmp(argv[i + 1], "menubar") == 0) { - toplevel = 0; - } - break; - } - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], toplevel ? "" - : NULL); - if (new == NULL) { - return TCL_ERROR; - } - - /* - * Initialize the data structure for the menu. - */ - - menuPtr = (TkMenu *) ckalloc(sizeof(TkMenu)); - menuPtr->tkwin = new; - menuPtr->display = Tk_Display(new); - menuPtr->interp = interp; - menuPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(menuPtr->tkwin), MenuWidgetCmd, - (ClientData) menuPtr, MenuCmdDeletedProc); - menuPtr->entries = NULL; - menuPtr->numEntries = 0; - menuPtr->active = -1; - menuPtr->border = NULL; - menuPtr->borderWidth = 0; - menuPtr->relief = TK_RELIEF_FLAT; - menuPtr->activeBorder = NULL; - menuPtr->activeBorderWidth = 0; - menuPtr->tkfont = NULL; - menuPtr->fg = NULL; - menuPtr->disabledFg = NULL; - menuPtr->activeFg = NULL; - menuPtr->indicatorFg = NULL; - menuPtr->tearOff = 1; - menuPtr->tearOffCommand = NULL; - menuPtr->cursor = None; - menuPtr->takeFocus = NULL; - menuPtr->postCommand = NULL; - menuPtr->postCommandGeneration = 0; - menuPtr->postedCascade = NULL; - menuPtr->nextInstancePtr = NULL; - menuPtr->masterMenuPtr = menuPtr; - menuPtr->menuType = UNKNOWN_TYPE; - menuPtr->menuFlags = 0; - menuPtr->parentTopLevelPtr = NULL; - menuPtr->menuTypeName = NULL; - menuPtr->title = NULL; - TkMenuInitializeDrawingFields(menuPtr); - - menuRefPtr = TkCreateMenuReferences(menuPtr->interp, - Tk_PathName(menuPtr->tkwin)); - menuRefPtr->menuPtr = menuPtr; - menuPtr->menuRefPtr = menuRefPtr; - if (TCL_OK != TkpNewMenu(menuPtr)) { - goto error; - } - - Tk_SetClass(menuPtr->tkwin, "Menu"); - TkSetClassProcs(menuPtr->tkwin, &menuClass, (ClientData) menuPtr); - Tk_CreateEventHandler(new, ExposureMask|StructureNotifyMask|ActivateMask, - TkMenuEventProc, (ClientData) menuPtr); - if (ConfigureMenu(interp, menuPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - /* - * If a menu has a parent menu pointing to it as a cascade entry, the - * parent menu needs to be told that this menu now exists so that - * the platform-part of the menu is correctly updated. - * - * If a menu has an instance and has cascade entries, then each cascade - * menu must also have a parallel instance. This is especially true on - * the Mac, where each menu has to have a separate title everytime it is in - * a menubar. For instance, say you have a menu .m1 with a cascade entry - * for .m2, where .m2 does not exist yet. You then put .m1 into a menubar. - * This creates a menubar instance for .m1, but since .m2 is not there, - * nothing else happens. When we go to create .m2, we hook it up properly - * with .m1. However, we now need to clone .m2 and assign the clone of .m2 - * to be the cascade entry for the clone of .m1. This is special case - * #1 listed in the introductory comment. - */ - - if (menuRefPtr->parentEntryPtr != NULL) { - TkMenuEntry *cascadeListPtr = menuRefPtr->parentEntryPtr; - TkMenuEntry *nextCascadePtr; - char *newMenuName; - char *newArgv[2]; - - while (cascadeListPtr != NULL) { - - nextCascadePtr = cascadeListPtr->nextCascadePtr; - - /* - * If we have a new master menu, and an existing cloned menu - * points to this menu in a cascade entry, we have to clone - * the new menu and point the entry to the clone instead - * of the menu we are creating. Otherwise, ConfigureMenuEntry - * will hook up the platform-specific cascade linkages now - * that the menu we are creating exists. - */ - - if ((menuPtr->masterMenuPtr != menuPtr) - || ((menuPtr->masterMenuPtr == menuPtr) - && ((cascadeListPtr->menuPtr->masterMenuPtr - == cascadeListPtr->menuPtr)))) { - newArgv[0] = "-menu"; - newArgv[1] = Tk_PathName(menuPtr->tkwin); - ConfigureMenuEntry(cascadeListPtr, 2, newArgv, - TK_CONFIG_ARGV_ONLY); - } else { - newMenuName = TkNewMenuName(menuPtr->interp, - Tk_PathName(cascadeListPtr->menuPtr->tkwin), - menuPtr); - CloneMenu(menuPtr, newMenuName, "normal"); - - /* - * Now we can set the new menu instance to be the cascade entry - * of the parent's instance. - */ - - newArgv[0] = "-menu"; - newArgv[1] = newMenuName; - ConfigureMenuEntry(cascadeListPtr, 2, newArgv, - TK_CONFIG_ARGV_ONLY); - if (newMenuName != NULL) { - ckfree(newMenuName); - } - } - cascadeListPtr = nextCascadePtr; - } - } - - /* - * If there already exist toplevel widgets that refer to this menu, - * find them and notify them so that they can reconfigure their - * geometry to reflect the menu. - */ - - if (menuRefPtr->topLevelListPtr != NULL) { - TkMenuTopLevelList *topLevelListPtr = menuRefPtr->topLevelListPtr; - TkMenuTopLevelList *nextPtr; - Tk_Window listtkwin; - while (topLevelListPtr != NULL) { - - /* - * Need to get the next pointer first. TkSetWindowMenuBar - * changes the list, so that the next pointer is different - * after calling it. - */ - - nextPtr = topLevelListPtr->nextPtr; - listtkwin = topLevelListPtr->tkwin; - TkSetWindowMenuBar(menuPtr->interp, listtkwin, - Tk_PathName(menuPtr->tkwin), Tk_PathName(menuPtr->tkwin)); - topLevelListPtr = nextPtr; - } - } - - interp->result = Tk_PathName(menuPtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(menuPtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * MenuWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -MenuWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about menu widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkMenu *menuPtr = (TkMenu *) clientData; - register TkMenuEntry *mePtr; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) menuPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0) - && (length >= 2)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " activate index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (menuPtr->active == index) { - goto done; - } - if (index >= 0) { - if ((menuPtr->entries[index]->type == SEPARATOR_ENTRY) - || (menuPtr->entries[index]->state == tkDisabledUid)) { - index = -1; - } - } - result = TkActivateMenuEntry(menuPtr, index); - } else if ((c == 'a') && (strncmp(argv[1], "add", length) == 0) - && (length >= 2)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " add type ?options?\"", (char *) NULL); - goto error; - } - if (MenuAddOrInsert(interp, menuPtr, (char *) NULL, - argc-2, argv+2) != TCL_OK) { - goto error; - } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, menuPtr->tkwin, tkMenuConfigSpecs, - (char *) menuPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "clone", length) == 0) - && (length >=2)) { - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " clone newMenuName ?menuType?\"", - (char *) NULL); - goto error; - } - result = CloneMenu(menuPtr, argv[2], (argc == 3) ? NULL : argv[3]); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuConfigSpecs, (char *) menuPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuConfigSpecs, (char *) menuPtr, argv[2], 0); - } else { - result = ConfigureMenu(interp, menuPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete first ?last?\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &first) != TCL_OK) { - goto error; - } - if (argc == 3) { - last = first; - } else { - if (TkGetMenuIndex(interp, menuPtr, argv[3], 0, &last) != TCL_OK) { - goto error; - } - } - if (menuPtr->tearOff && (first == 0)) { - - /* - * Sorry, can't delete the tearoff entry; must reconfigure - * the menu. - */ - - first = 1; - } - if ((first < 0) || (last < first)) { - goto done; - } - DeleteMenuCloneEntries(menuPtr, first, last); - } else if ((c == 'e') && (length >= 7) - && (strncmp(argv[1], "entrycget", length) == 0)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " entrycget index option\"", - (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - Tcl_Preserve((ClientData) mePtr); - result = Tk_ConfigureValue(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, argv[3], - COMMAND_MASK << mePtr->type); - Tcl_Release((ClientData) mePtr); - } else if ((c == 'e') && (length >= 7) - && (strncmp(argv[1], "entryconfigure", length) == 0)) { - int index; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " entryconfigure index ?option value ...?\"", - (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - Tcl_Preserve((ClientData) mePtr); - if (argc == 3) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, (char *) NULL, - COMMAND_MASK << mePtr->type); - } else if (argc == 4) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, argv[3], - COMMAND_MASK << mePtr->type); - } else { - result = ConfigureMenuCloneEntries(interp, menuPtr, index, - argc-3, argv+3, - TK_CONFIG_ARGV_ONLY | COMMAND_MASK << mePtr->type); - } - Tcl_Release((ClientData) mePtr); - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index string\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - interp->result = "none"; - } else { - sprintf(interp->result, "%d", index); - } - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index type ?options?\"", (char *) NULL); - goto error; - } - if (MenuAddOrInsert(interp, menuPtr, argv[2], - argc-3, argv+3) != TCL_OK) { - goto error; - } - } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " invoke index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - result = TkInvokeMenu(interp, menuPtr, index); - } else if ((c == 'p') && (strncmp(argv[1], "post", length) == 0) - && (length == 4)) { - int x, y; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " post x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - - /* - * Tearoff menus are posted differently on Mac and Windows than - * non-tearoffs. TkpPostMenu does not actually map the menu's - * window on those platforms, and popup menus have to be - * handled specially. - */ - - if (menuPtr->menuType != TEAROFF_MENU) { - result = TkpPostMenu(interp, menuPtr, x, y); - } else { - result = TkPostTearoffMenu(interp, menuPtr, x, y); - } - } else if ((c == 'p') && (strncmp(argv[1], "postcascade", length) == 0) - && (length > 4)) { - int index; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " postcascade index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if ((index < 0) || (menuPtr->entries[index]->type != CASCADE_ENTRY)) { - result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); - } else { - result = TkPostSubmenu(interp, menuPtr, menuPtr->entries[index]); - } - } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) { - int index; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " type index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - switch (mePtr->type) { - case COMMAND_ENTRY: - interp->result = "command"; - break; - case SEPARATOR_ENTRY: - interp->result = "separator"; - break; - case CHECK_BUTTON_ENTRY: - interp->result = "checkbutton"; - break; - case RADIO_BUTTON_ENTRY: - interp->result = "radiobutton"; - break; - case CASCADE_ENTRY: - interp->result = "cascade"; - break; - case TEAROFF_ENTRY: - interp->result = "tearoff"; - break; - } - } else if ((c == 'u') && (strncmp(argv[1], "unpost", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " unpost\"", (char *) NULL); - goto error; - } - Tk_UnmapWindow(menuPtr->tkwin); - result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); - } else if ((c == 'y') && (strncmp(argv[1], "yposition", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " yposition index\"", (char *) NULL); - goto error; - } - result = MenuDoYPosition(interp, menuPtr, argv[2]); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be activate, add, cget, clone, configure, delete, ", - "entrycget, entryconfigure, index, insert, invoke, ", - "post, postcascade, type, unpost, or yposition", - (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) menuPtr); - return result; - - error: - Tcl_Release((ClientData) menuPtr); - return TCL_ERROR; -} - - -/* - *---------------------------------------------------------------------- - * - * TkInvokeMenu -- - * - * Given a menu and an index, takes the appropriate action for the - * entry associated with that index. - * - * Results: - * Standard Tcl result. - * - * Side effects: - * Commands may get excecuted; variables may get set; sub-menus may - * get posted. - * - *---------------------------------------------------------------------- - */ - -int -TkInvokeMenu(interp, menuPtr, index) - Tcl_Interp *interp; /* The interp that the menu lives in. */ - TkMenu *menuPtr; /* The menu we are invoking. */ - int index; /* The zero based index of the item we - * are invoking */ -{ - int result = TCL_OK; - TkMenuEntry *mePtr; - - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - if (mePtr->state == tkDisabledUid) { - goto done; - } - Tcl_Preserve((ClientData) mePtr); - if (mePtr->type == TEAROFF_ENTRY) { - Tcl_DString commandDString; - - Tcl_DStringInit(&commandDString); - Tcl_DStringAppendElement(&commandDString, "tkTearOffMenu"); - Tcl_DStringAppendElement(&commandDString, Tk_PathName(menuPtr->tkwin)); - result = Tcl_Eval(interp, Tcl_DStringValue(&commandDString)); - Tcl_DStringFree(&commandDString); - } else if (mePtr->type == CHECK_BUTTON_ENTRY) { - if (mePtr->entryFlags & ENTRY_SELECTED) { - if (Tcl_SetVar(interp, mePtr->name, mePtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } else { - if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } - } else if (mePtr->type == RADIO_BUTTON_ENTRY) { - if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } - if ((result == TCL_OK) && (mePtr->command != NULL)) { - result = TkCopyAndGlobalEval(interp, mePtr->command); - } - Tcl_Release((ClientData) mePtr); - done: - return result; -} - - - -/* - *---------------------------------------------------------------------- - * - * DestroyMenuInstance -- - * - * This procedure is invoked by TkDestroyMenu - * to clean up the internal structure of a menu at a safe time - * (when no-one is using it anymore). Only takes care of one instance - * of the menu. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the menu is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyMenuInstance(menuPtr) - TkMenu *menuPtr; /* Info about menu widget. */ -{ - int i, numEntries = menuPtr->numEntries; - TkMenu *menuInstancePtr; - TkMenuEntry *cascadePtr, *nextCascadePtr; - char *newArgv[2]; - TkMenu *parentMasterMenuPtr; - TkMenuEntry *parentMasterEntryPtr; - TkMenu *parentMenuPtr; - - /* - * If the menu has any cascade menu entries pointing to it, the cascade - * entries need to be told that the menu is going away. We need to clear - * the menu ptr field in the menu reference at this point in the code - * so that everything else can forget about this menu properly. We also - * need to reset -menu field of all entries that are not master menus - * back to this entry name if this is a master menu pointed to by another - * master menu. If there is a clone menu that points to this menu, - * then this menu is itself a clone, so when this menu goes away, - * the -menu field of the pointing entry must be set back to this - * menu's master menu name so that later if another menu is created - * the cascade hierarchy can be maintained. - */ - - TkpDestroyMenu(menuPtr); - cascadePtr = menuPtr->menuRefPtr->parentEntryPtr; - menuPtr->menuRefPtr->menuPtr = NULL; - TkFreeMenuReferences(menuPtr->menuRefPtr); - - for (; cascadePtr != NULL; cascadePtr = nextCascadePtr) { - parentMenuPtr = cascadePtr->menuPtr; - nextCascadePtr = cascadePtr->nextCascadePtr; - - if (menuPtr->masterMenuPtr != menuPtr) { - parentMasterMenuPtr = cascadePtr->menuPtr->masterMenuPtr; - parentMasterEntryPtr = - parentMasterMenuPtr->entries[cascadePtr->index]; - newArgv[0] = "-menu"; - newArgv[1] = parentMasterEntryPtr->name; - ConfigureMenuEntry(cascadePtr, 2, newArgv, TK_CONFIG_ARGV_ONLY); - } else { - ConfigureMenuEntry(cascadePtr, 0, (char **) NULL, 0); - } - } - - if (menuPtr->masterMenuPtr != menuPtr) { - for (menuInstancePtr = menuPtr->masterMenuPtr; - menuInstancePtr != NULL; - menuInstancePtr = menuInstancePtr->nextInstancePtr) { - if (menuInstancePtr->nextInstancePtr == menuPtr) { - menuInstancePtr->nextInstancePtr = - menuInstancePtr->nextInstancePtr->nextInstancePtr; - break; - } - } - } else if (menuPtr->nextInstancePtr != NULL) { - panic("Attempting to delete master menu when there are still clones."); - } - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - for (i = numEntries - 1; i >= 0; i--) { - DestroyMenuEntry((char *) menuPtr->entries[i]); - } - if (menuPtr->entries != NULL) { - ckfree((char *) menuPtr->entries); - } - TkMenuFreeDrawOptions(menuPtr); - Tk_FreeOptions(tkMenuConfigSpecs, (char *) menuPtr, menuPtr->display, 0); - - Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC); -} - -/* - *---------------------------------------------------------------------- - * - * TkDestroyMenu -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a menu at a safe time - * (when no-one is using it anymore). If called on a master instance, - * destroys all of the slave instances. If called on a non-master - * instance, just destroys that instance. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the menu is freed up. - * - *---------------------------------------------------------------------- - */ - -void -TkDestroyMenu(menuPtr) - TkMenu *menuPtr; /* Info about menu widget. */ -{ - TkMenu *menuInstancePtr; - TkMenuTopLevelList *topLevelListPtr, *nextTopLevelPtr; - - if (menuPtr->menuFlags & MENU_DELETION_PENDING) { - return; - } - - /* - * Now destroy all non-tearoff instances of this menu if this is a - * parent menu. Is this loop safe enough? Are there going to be - * destroy bindings on child menus which kill the parent? If not, - * we have to do a slightly more complex scheme. - */ - - if (menuPtr->masterMenuPtr == menuPtr) { - menuPtr->menuFlags |= MENU_DELETION_PENDING; - while (menuPtr->nextInstancePtr != NULL) { - menuInstancePtr = menuPtr->nextInstancePtr; - menuPtr->nextInstancePtr = menuInstancePtr->nextInstancePtr; - if (menuInstancePtr->tkwin != NULL) { - Tk_DestroyWindow(menuInstancePtr->tkwin); - } - } - menuPtr->menuFlags &= ~MENU_DELETION_PENDING; - } - - /* - * If any toplevel widgets have this menu as their menubar, - * the geometry of the window may have to be recalculated. - */ - - topLevelListPtr = menuPtr->menuRefPtr->topLevelListPtr; - while (topLevelListPtr != NULL) { - nextTopLevelPtr = topLevelListPtr->nextPtr; - TkpSetWindowMenuBar(topLevelListPtr->tkwin, NULL); - topLevelListPtr = nextTopLevelPtr; - } - DestroyMenuInstance(menuPtr); -} - -/* - *---------------------------------------------------------------------- - * - * UnhookCascadeEntry -- - * - * This entry is removed from the list of entries that point to the - * cascade menu. This is done in preparation for changing the menu - * that this entry points to. - * - * Results: - * None - * - * Side effects: - * The appropriate lists are modified. - * - *---------------------------------------------------------------------- - */ - -static void -UnhookCascadeEntry(mePtr) - TkMenuEntry *mePtr; /* The cascade entry we are removing - * from the cascade list. */ -{ - TkMenuEntry *cascadeEntryPtr; - TkMenuEntry *prevCascadePtr; - TkMenuReferences *menuRefPtr; - - menuRefPtr = mePtr->childMenuRefPtr; - if (menuRefPtr == NULL) { - return; - } - - cascadeEntryPtr = menuRefPtr->parentEntryPtr; - if (cascadeEntryPtr == NULL) { - return; - } - - /* - * Singularly linked list deletion. The two special cases are - * 1. one element; 2. The first element is the one we want. - */ - - if (cascadeEntryPtr == mePtr) { - if (cascadeEntryPtr->nextCascadePtr == NULL) { - - /* - * This is the last menu entry which points to this - * menu, so we need to clear out the list pointer in the - * cascade itself. - */ - - menuRefPtr->parentEntryPtr = NULL; - TkFreeMenuReferences(menuRefPtr); - } else { - menuRefPtr->parentEntryPtr = cascadeEntryPtr->nextCascadePtr; - } - mePtr->nextCascadePtr = NULL; - } else { - for (prevCascadePtr = cascadeEntryPtr, - cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr; - cascadeEntryPtr != NULL; - prevCascadePtr = cascadeEntryPtr, - cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - if (cascadeEntryPtr == mePtr){ - prevCascadePtr->nextCascadePtr = - cascadeEntryPtr->nextCascadePtr; - cascadeEntryPtr->nextCascadePtr = NULL; - break; - } - } - } - mePtr->childMenuRefPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyMenuEntry -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a menu entry at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the menu entry is freed. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyMenuEntry(memPtr) - char *memPtr; /* Pointer to entry to be freed. */ -{ - register TkMenuEntry *mePtr = (TkMenuEntry *) memPtr; - TkMenu *menuPtr = mePtr->menuPtr; - - if (menuPtr->postedCascade == mePtr) { - - /* - * Ignore errors while unposting the menu, since it's possible - * that the menu has already been deleted and the unpost will - * generate an error. - */ - - TkPostSubmenu(menuPtr->interp, menuPtr, (TkMenuEntry *) NULL); - } - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (mePtr->type == CASCADE_ENTRY) { - UnhookCascadeEntry(mePtr); - } - if (mePtr->image != NULL) { - Tk_FreeImage(mePtr->image); - } - if (mePtr->selectImage != NULL) { - Tk_FreeImage(mePtr->selectImage); - } - if (mePtr->name != NULL) { - Tcl_UntraceVar(menuPtr->interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, (ClientData) mePtr); - } - TkpDestroyMenuEntry(mePtr); - TkMenuEntryFreeDrawOptions(mePtr); - Tk_FreeOptions(tkMenuEntryConfigSpecs, (char *) mePtr, menuPtr->display, - (COMMAND_MASK << mePtr->type)); - ckfree((char *) mePtr); -} - -/* - *--------------------------------------------------------------------------- - * - * MenuWorldChanged -- - * - * This procedure is called when the world has changed in some - * way (such as the fonts in the system changing) and the widget needs - * to recompute all its graphics contexts and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Menu will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -MenuWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - TkMenu *menuPtr = (TkMenu *) instanceData; - int i; - - TkMenuConfigureDrawOptions(menuPtr); - for (i = 0; i < menuPtr->numEntries; i++) { - TkMenuConfigureEntryDrawOptions(menuPtr->entries[i], - menuPtr->entries[i]->index); - TkpConfigureMenuEntry(menuPtr->entries[i]); - } -} - - -/* - *---------------------------------------------------------------------- - * - * ConfigureMenu -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a menu widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, font, etc. get set - * for menuPtr; old resources get freed, if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureMenu(interp, menuPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkMenu *menuPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - int i; - TkMenu* menuListPtr; - - for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; - menuListPtr = menuListPtr->nextInstancePtr) { - - if (Tk_ConfigureWidget(interp, menuListPtr->tkwin, - tkMenuConfigSpecs, argc, argv, (char *) menuListPtr, - flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * When a menu is created, the type is in all of the arguments - * to the menu command. Let Tk_ConfigureWidget take care of - * parsing them, and then set the type after we can look at - * the type string. Once set, a menu's type cannot be changed - */ - - if (menuListPtr->menuType == UNKNOWN_TYPE) { - if (strcmp(menuListPtr->menuTypeName, "menubar") == 0) { - menuListPtr->menuType = MENUBAR; - } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { - menuListPtr->menuType = TEAROFF_MENU; - } else { - menuListPtr->menuType = MASTER_MENU; - } - } - - /* - * Depending on the -tearOff option, make sure that there is or - * isn't an initial tear-off entry at the beginning of the menu. - */ - - if (menuListPtr->tearOff) { - if ((menuListPtr->numEntries == 0) - || (menuListPtr->entries[0]->type != TEAROFF_ENTRY)) { - if (MenuNewEntry(menuListPtr, 0, TEAROFF_ENTRY) == NULL) { - return TCL_ERROR; - } - } - } else if ((menuListPtr->numEntries > 0) - && (menuListPtr->entries[0]->type == TEAROFF_ENTRY)) { - int i; - - Tcl_EventuallyFree((ClientData) menuListPtr->entries[0], - DestroyMenuEntry); - for (i = 0; i < menuListPtr->numEntries - 1; i++) { - menuListPtr->entries[i] = menuListPtr->entries[i + 1]; - menuListPtr->entries[i]->index = i; - } - menuListPtr->numEntries--; - if (menuListPtr->numEntries == 0) { - ckfree((char *) menuListPtr->entries); - menuListPtr->entries = NULL; - } - } - - TkMenuConfigureDrawOptions(menuListPtr); - - /* - * Configure the new window to be either a pop-up menu - * or a tear-off menu. - * We don't do this for menubars since they are not toplevel - * windows. Also, since this gets called before CloneMenu has - * a chance to set the menuType field, we have to look at the - * menuTypeName field to tell that this is a menu bar. - */ - - if (strcmp(menuListPtr->menuTypeName, "normal") == 0) { - TkpMakeMenuWindow(menuListPtr->tkwin, 1); - } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { - TkpMakeMenuWindow(menuListPtr->tkwin, 0); - } - - /* - * After reconfiguring a menu, we need to reconfigure all of the - * entries in the menu, since some of the things in the children - * (such as graphics contexts) may have to change to reflect changes - * in the parent. - */ - - for (i = 0; i < menuListPtr->numEntries; i++) { - TkMenuEntry *mePtr; - - mePtr = menuListPtr->entries[i]; - ConfigureMenuEntry(mePtr, 0, - (char **) NULL, TK_CONFIG_ARGV_ONLY - | COMMAND_MASK << mePtr->type); - } - - TkEventuallyRecomputeMenu(menuListPtr); - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureMenuEntry -- - * - * This procedure is called to process an argv/argc list in order - * to configure (or reconfigure) one entry in a menu. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information such as label and accelerator get - * set for mePtr; old resources get freed, if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureMenuEntry(mePtr, argc, argv, flags) - register TkMenuEntry *mePtr; /* Information about menu entry; may - * or may not already have values for - * some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Additional flags to pass to - * Tk_ConfigureWidget. */ -{ - TkMenu *menuPtr = mePtr->menuPtr; - int index = mePtr->index; - Tk_Image image; - - /* - * If this entry is a check button or radio button, then remove - * its old trace procedure. - */ - - if ((mePtr->name != NULL) - && ((mePtr->type == CHECK_BUTTON_ENTRY) - || (mePtr->type == RADIO_BUTTON_ENTRY))) { - Tcl_UntraceVar(menuPtr->interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, (ClientData) mePtr); - } - - if (menuPtr->tkwin != NULL) { - if (Tk_ConfigureWidget(menuPtr->interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, argc, argv, (char *) mePtr, - flags | (COMMAND_MASK << mePtr->type)) != TCL_OK) { - return TCL_ERROR; - } - } - - /* - * The code below handles special configuration stuff not taken - * care of by Tk_ConfigureWidget, such as special processing for - * defaults, sizing strings, graphics contexts, etc. - */ - - if (mePtr->label == NULL) { - mePtr->labelLength = 0; - } else { - mePtr->labelLength = strlen(mePtr->label); - } - if (mePtr->accel == NULL) { - mePtr->accelLength = 0; - } else { - mePtr->accelLength = strlen(mePtr->accel); - } - - /* - * If this is a cascade entry, the platform-specific data of the child - * menu has to be updated. Also, the links that point to parents and - * cascades have to be updated. - */ - - if ((mePtr->type == CASCADE_ENTRY) && (mePtr->name != NULL)) { - TkMenuEntry *cascadeEntryPtr; - TkMenu *cascadeMenuPtr; - int alreadyThere; - TkMenuReferences *menuRefPtr; - char *oldHashKey = NULL; /* Initialization only needed to - * prevent compiler warning. */ - - /* - * This is a cascade entry. If the menu that the cascade entry - * is pointing to has changed, we need to remove this entry - * from the list of entries pointing to the old menu, and add a - * cascade reference to the list of entries pointing to the - * new menu. - * - * BUG: We are not recloning for special case #3 yet. - */ - - if (mePtr->childMenuRefPtr != NULL) { - oldHashKey = Tcl_GetHashKey(TkGetMenuHashTable(menuPtr->interp), - mePtr->childMenuRefPtr->hashEntryPtr); - if (strcmp(oldHashKey, mePtr->name) != 0) { - UnhookCascadeEntry(mePtr); - } - } - - if ((mePtr->childMenuRefPtr == NULL) - || (strcmp(oldHashKey, mePtr->name) != 0)) { - menuRefPtr = TkCreateMenuReferences(menuPtr->interp, - mePtr->name); - cascadeMenuPtr = menuRefPtr->menuPtr; - mePtr->childMenuRefPtr = menuRefPtr; - - if (menuRefPtr->parentEntryPtr == NULL) { - menuRefPtr->parentEntryPtr = mePtr; - } else { - alreadyThere = 0; - for (cascadeEntryPtr = menuRefPtr->parentEntryPtr; - cascadeEntryPtr != NULL; - cascadeEntryPtr = - cascadeEntryPtr->nextCascadePtr) { - if (cascadeEntryPtr == mePtr) { - alreadyThere = 1; - break; - } - } - - /* - * Put the item at the front of the list. - */ - - if (!alreadyThere) { - mePtr->nextCascadePtr = menuRefPtr->parentEntryPtr; - menuRefPtr->parentEntryPtr = mePtr; - } - } - } - } - - if (TkMenuConfigureEntryDrawOptions(mePtr, index) != TCL_OK) { - return TCL_ERROR; - } - - if (TkpConfigureMenuEntry(mePtr) != TCL_OK) { - return TCL_ERROR; - } - - if ((mePtr->type == CHECK_BUTTON_ENTRY) - || (mePtr->type == RADIO_BUTTON_ENTRY)) { - char *value; - - if (mePtr->name == NULL) { - mePtr->name = - (char *) ckalloc((unsigned) (mePtr->labelLength + 1)); - strcpy(mePtr->name, (mePtr->label == NULL) ? "" : mePtr->label); - } - if (mePtr->onValue == NULL) { - mePtr->onValue = (char *) ckalloc((unsigned) - (mePtr->labelLength + 1)); - strcpy(mePtr->onValue, (mePtr->label == NULL) ? "" : mePtr->label); - } - - /* - * Select the entry if the associated variable has the - * appropriate value, initialize the variable if it doesn't - * exist, then set a trace on the variable to monitor future - * changes to its value. - */ - - value = Tcl_GetVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY); - mePtr->entryFlags &= ~ENTRY_SELECTED; - if (value != NULL) { - if (strcmp(value, mePtr->onValue) == 0) { - mePtr->entryFlags |= ENTRY_SELECTED; - } - } else { - Tcl_SetVar(menuPtr->interp, mePtr->name, - (mePtr->type == CHECK_BUTTON_ENTRY) ? mePtr->offValue : "", - TCL_GLOBAL_ONLY); - } - Tcl_TraceVar(menuPtr->interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, (ClientData) mePtr); - } - - /* - * Get the images for the entry, if there are any. Allocate the - * new images before freeing the old ones, so that the reference - * counts don't go to zero and cause image data to be discarded. - */ - - if (mePtr->imageString != NULL) { - image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->imageString, - TkMenuImageProc, (ClientData) mePtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (mePtr->image != NULL) { - Tk_FreeImage(mePtr->image); - } - mePtr->image = image; - if (mePtr->selectImageString != NULL) { - image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->selectImageString, - TkMenuSelectImageProc, (ClientData) mePtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (mePtr->selectImage != NULL) { - Tk_FreeImage(mePtr->selectImage); - } - mePtr->selectImage = image; - - TkEventuallyRecomputeMenu(menuPtr); - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureMenuCloneEntries -- - * - * Calls ConfigureMenuEntry for each menu in the clone chain. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information such as label and accelerator get - * set for mePtr; old resources get freed, if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - TkMenu *menuPtr; /* Information about whole menu. */ - int index; /* Index of mePtr within menuPtr's - * entries. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Additional flags to pass to - * Tk_ConfigureWidget. */ -{ - TkMenuEntry *mePtr; - TkMenu *menuListPtr; - char *oldCascadeName = NULL, *newMenuName = NULL; - int cascadeEntryChanged; - TkMenuReferences *oldCascadeMenuRefPtr, *cascadeMenuRefPtr = NULL; - - /* - * Cascades are kind of tricky here. This is special case #3 in the comment - * at the top of this file. Basically, if a menu is the master menu of a - * clone chain, and has an entry with a cascade menu, the clones of - * the menu will point to clones of the cascade menu. We have - * to destroy the clones of the cascades, clone the new cascade - * menu, and configure the entry to point to the new clone. - */ - - mePtr = menuPtr->masterMenuPtr->entries[index]; - if (mePtr->type == CASCADE_ENTRY) { - oldCascadeName = mePtr->name; - } - - if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { - return TCL_ERROR; - } - - cascadeEntryChanged = (mePtr->type == CASCADE_ENTRY) - && (oldCascadeName != mePtr->name); - - if (cascadeEntryChanged) { - newMenuName = mePtr->name; - if (newMenuName != NULL) { - cascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, - mePtr->name); - } - } - - for (menuListPtr = menuPtr->masterMenuPtr->nextInstancePtr; - menuListPtr != NULL; - menuListPtr = menuListPtr->nextInstancePtr) { - - mePtr = menuListPtr->entries[index]; - - if (cascadeEntryChanged && (mePtr->name != NULL)) { - oldCascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, - mePtr->name); - - if ((oldCascadeMenuRefPtr != NULL) - && (oldCascadeMenuRefPtr->menuPtr != NULL)) { - RecursivelyDeleteMenu(oldCascadeMenuRefPtr->menuPtr); - } - } - - if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { - return TCL_ERROR; - } - - if (cascadeEntryChanged && (newMenuName != NULL)) { - if (cascadeMenuRefPtr->menuPtr != NULL) { - char *newArgV[2]; - char *newCloneName; - - newCloneName = TkNewMenuName(menuPtr->interp, - Tk_PathName(menuListPtr->tkwin), - cascadeMenuRefPtr->menuPtr); - CloneMenu(cascadeMenuRefPtr->menuPtr, newCloneName, - "normal"); - - newArgV[0] = "-menu"; - newArgV[1] = newCloneName; - ConfigureMenuEntry(mePtr, 2, newArgV, flags); - ckfree(newCloneName); - } - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkGetMenuIndex -- - * - * Parse a textual index into a menu and return the numerical - * index of the indicated entry. - * - * Results: - * A standard Tcl result. If all went well, then *indexPtr is - * filled in with the entry index corresponding to string - * (ranges from -1 to the number of entries in the menu minus - * one). Otherwise an error message is left in interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkGetMenuIndex(interp, menuPtr, string, lastOK, indexPtr) - Tcl_Interp *interp; /* For error messages. */ - TkMenu *menuPtr; /* Menu for which the index is being - * specified. */ - char *string; /* Specification of an entry in menu. See - * manual entry for valid .*/ - int lastOK; /* Non-zero means its OK to return index - * just *after* last entry. */ - int *indexPtr; /* Where to store converted relief. */ -{ - int i; - - if ((string[0] == 'a') && (strcmp(string, "active") == 0)) { - *indexPtr = menuPtr->active; - return TCL_OK; - } - - if (((string[0] == 'l') && (strcmp(string, "last") == 0)) - || ((string[0] == 'e') && (strcmp(string, "end") == 0))) { - *indexPtr = menuPtr->numEntries - ((lastOK) ? 0 : 1); - return TCL_OK; - } - - if ((string[0] == 'n') && (strcmp(string, "none") == 0)) { - *indexPtr = -1; - return TCL_OK; - } - - if (string[0] == '@') { - if (GetIndexFromCoords(interp, menuPtr, string, indexPtr) - == TCL_OK) { - return TCL_OK; - } - } - - if (isdigit(UCHAR(string[0]))) { - if (Tcl_GetInt(interp, string, &i) == TCL_OK) { - if (i >= menuPtr->numEntries) { - if (lastOK) { - i = menuPtr->numEntries; - } else { - i = menuPtr->numEntries-1; - } - } else if (i < 0) { - i = -1; - } - *indexPtr = i; - return TCL_OK; - } - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - } - - for (i = 0; i < menuPtr->numEntries; i++) { - char *label; - - label = menuPtr->entries[i]->label; - if ((label != NULL) - && (Tcl_StringMatch(menuPtr->entries[i]->label, string))) { - *indexPtr = i; - return TCL_OK; - } - } - - Tcl_AppendResult(interp, "bad menu entry index \"", - string, "\"", (char *) NULL); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * MenuCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -MenuCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkMenu *menuPtr = (TkMenu *) clientData; - Tk_Window tkwin = menuPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - menuPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *---------------------------------------------------------------------- - * - * MenuNewEntry -- - * - * This procedure allocates and initializes a new menu entry. - * - * Results: - * The return value is a pointer to a new menu entry structure, - * which has been malloc-ed, initialized, and entered into the - * entry array for the menu. - * - * Side effects: - * Storage gets allocated. - * - *---------------------------------------------------------------------- - */ - -static TkMenuEntry * -MenuNewEntry(menuPtr, index, type) - TkMenu *menuPtr; /* Menu that will hold the new entry. */ - int index; /* Where in the menu the new entry is to - * go. */ - int type; /* The type of the new entry. */ -{ - TkMenuEntry *mePtr; - TkMenuEntry **newEntries; - int i; - - /* - * Create a new array of entries with an empty slot for the - * new entry. - */ - - newEntries = (TkMenuEntry **) ckalloc((unsigned) - ((menuPtr->numEntries+1)*sizeof(TkMenuEntry *))); - for (i = 0; i < index; i++) { - newEntries[i] = menuPtr->entries[i]; - } - for ( ; i < menuPtr->numEntries; i++) { - newEntries[i+1] = menuPtr->entries[i]; - newEntries[i+1]->index = i + 1; - } - if (menuPtr->numEntries != 0) { - ckfree((char *) menuPtr->entries); - } - menuPtr->entries = newEntries; - menuPtr->numEntries++; - mePtr = (TkMenuEntry *) ckalloc(sizeof(TkMenuEntry)); - menuPtr->entries[index] = mePtr; - mePtr->type = type; - mePtr->menuPtr = menuPtr; - mePtr->label = NULL; - mePtr->labelLength = 0; - mePtr->underline = -1; - mePtr->bitmap = None; - mePtr->imageString = NULL; - mePtr->image = NULL; - mePtr->selectImageString = NULL; - mePtr->selectImage = NULL; - mePtr->accel = NULL; - mePtr->accelLength = 0; - mePtr->state = tkNormalUid; - mePtr->border = NULL; - mePtr->fg = NULL; - mePtr->activeBorder = NULL; - mePtr->activeFg = NULL; - mePtr->tkfont = NULL; - mePtr->indicatorOn = 1; - mePtr->indicatorFg = NULL; - mePtr->columnBreak = 0; - mePtr->hideMargin = 0; - mePtr->command = NULL; - mePtr->name = NULL; - mePtr->childMenuRefPtr = NULL; - mePtr->onValue = NULL; - mePtr->offValue = NULL; - mePtr->entryFlags = 0; - mePtr->index = index; - mePtr->nextCascadePtr = NULL; - TkMenuInitializeEntryDrawingFields(mePtr); - if (TkpMenuNewEntry(mePtr) != TCL_OK) { - ckfree((char *) mePtr); - return NULL; - } - - return mePtr; -} - -/* - *---------------------------------------------------------------------- - * - * MenuAddOrInsert -- - * - * This procedure does all of the work of the "add" and "insert" - * widget commands, allowing the code for these to be shared. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * A new menu entry is created in menuPtr. - * - *---------------------------------------------------------------------- - */ - -static int -MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - TkMenu *menuPtr; /* Widget in which to create new - * entry. */ - char *indexString; /* String describing index at which - * to insert. NULL means insert at - * end. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments to command: first arg - * is type of entry, others are - * config options. */ -{ - int c, type, index; - size_t length; - TkMenuEntry *mePtr; - TkMenu *menuListPtr; - - if (indexString != NULL) { - if (TkGetMenuIndex(interp, menuPtr, indexString, 1, &index) - != TCL_OK) { - return TCL_ERROR; - } - } else { - index = menuPtr->numEntries; - } - if (index < 0) { - Tcl_AppendResult(interp, "bad index \"", indexString, "\"", - (char *) NULL); - return TCL_ERROR; - } - if (menuPtr->tearOff && (index == 0)) { - index = 1; - } - - /* - * Figure out the type of the new entry. - */ - - c = argv[0][0]; - length = strlen(argv[0]); - if ((c == 'c') && (strncmp(argv[0], "cascade", length) == 0) - && (length >= 2)) { - type = CASCADE_ENTRY; - } else if ((c == 'c') && (strncmp(argv[0], "checkbutton", length) == 0) - && (length >= 2)) { - type = CHECK_BUTTON_ENTRY; - } else if ((c == 'c') && (strncmp(argv[0], "command", length) == 0) - && (length >= 2)) { - type = COMMAND_ENTRY; - } else if ((c == 'r') - && (strncmp(argv[0], "radiobutton", length) == 0)) { - type = RADIO_BUTTON_ENTRY; - } else if ((c == 's') - && (strncmp(argv[0], "separator", length) == 0)) { - type = SEPARATOR_ENTRY; - } else { - Tcl_AppendResult(interp, "bad menu entry type \"", - argv[0], "\": must be cascade, checkbutton, ", - "command, radiobutton, or separator", (char *) NULL); - return TCL_ERROR; - } - - /* - * Now we have to add an entry for every instance related to this menu. - */ - - for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; - menuListPtr = menuListPtr->nextInstancePtr) { - - mePtr = MenuNewEntry(menuListPtr, index, type); - if (mePtr == NULL) { - return TCL_ERROR; - } - if (ConfigureMenuEntry(mePtr, argc-1, argv+1, 0) != TCL_OK) { - TkMenu *errorMenuPtr; - int i; - - for (errorMenuPtr = menuPtr->masterMenuPtr; - errorMenuPtr != NULL; - errorMenuPtr = errorMenuPtr->nextInstancePtr) { - Tcl_EventuallyFree((ClientData) errorMenuPtr->entries[index], - DestroyMenuEntry); - for (i = index; i < errorMenuPtr->numEntries - 1; i++) { - errorMenuPtr->entries[i] = errorMenuPtr->entries[i + 1]; - errorMenuPtr->entries[i]->index = i; - } - errorMenuPtr->numEntries--; - if (errorMenuPtr->numEntries == 0) { - ckfree((char *) errorMenuPtr->entries); - errorMenuPtr->entries = NULL; - } - if (errorMenuPtr == menuListPtr) { - break; - } - } - return TCL_ERROR; - } - - /* - * If a menu has cascades, then every instance of the menu has - * to have its own parallel cascade structure. So adding an - * entry to a menu with clones means that the menu that the - * entry points to has to be cloned for every clone the - * master menu has. This is special case #2 in the comment - * at the top of this file. - */ - - if ((menuPtr != menuListPtr) && (type == CASCADE_ENTRY)) { - if ((mePtr->name != NULL) && (mePtr->childMenuRefPtr != NULL) - && (mePtr->childMenuRefPtr->menuPtr != NULL)) { - TkMenu *cascadeMenuPtr = - mePtr->childMenuRefPtr->menuPtr->masterMenuPtr; - char *newCascadeName; - char *newArgv[2]; - TkMenuReferences *menuRefPtr; - - newCascadeName = TkNewMenuName(menuListPtr->interp, - Tk_PathName(menuListPtr->tkwin), - cascadeMenuPtr); - CloneMenu(cascadeMenuPtr, newCascadeName, "normal"); - - menuRefPtr = TkFindMenuReferences(menuListPtr->interp, - newCascadeName); - if (menuRefPtr == NULL) { - panic("CloneMenu failed inside of MenuAddOrInsert."); - } - newArgv[0] = "-menu"; - newArgv[1] = newCascadeName; - ConfigureMenuEntry(mePtr, 2, newArgv, 0); - ckfree(newCascadeName); - } - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * MenuVarProc -- - * - * This procedure is invoked when someone changes the - * state variable associated with a radiobutton or checkbutton - * menu entry. The entry's selected state is set to match - * the value of the variable. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The menu entry may become selected or deselected. - * - *-------------------------------------------------------------- - */ - -static char * -MenuVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about menu entry. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* First part of variable's name. */ - char *name2; /* Second part of variable's name. */ - int flags; /* Describes what just happened. */ -{ - TkMenuEntry *mePtr = (TkMenuEntry *) clientData; - TkMenu *menuPtr; - char *value; - - menuPtr = mePtr->menuPtr; - - /* - * If the variable is being unset, then re-establish the - * trace unless the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - mePtr->entryFlags &= ~ENTRY_SELECTED; - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, clientData); - } - TkpConfigureMenuEntry(mePtr); - TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - return (char *) NULL; - } - - /* - * Use the value of the variable to update the selected status of - * the menu entry. - */ - - value = Tcl_GetVar(interp, mePtr->name, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (strcmp(value, mePtr->onValue) == 0) { - if (mePtr->entryFlags & ENTRY_SELECTED) { - return (char *) NULL; - } - mePtr->entryFlags |= ENTRY_SELECTED; - } else if (mePtr->entryFlags & ENTRY_SELECTED) { - mePtr->entryFlags &= ~ENTRY_SELECTED; - } else { - return (char *) NULL; - } - TkpConfigureMenuEntry(mePtr); - TkEventuallyRedrawMenu(menuPtr, mePtr); - return (char *) NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkActivateMenuEntry -- - * - * This procedure is invoked to make a particular menu entry - * the active one, deactivating any other entry that might - * currently be active. - * - * Results: - * The return value is a standard Tcl result (errors can occur - * while posting and unposting submenus). - * - * Side effects: - * Menu entries get redisplayed, and the active entry changes. - * Submenus may get posted and unposted. - * - *---------------------------------------------------------------------- - */ - -int -TkActivateMenuEntry(menuPtr, index) - register TkMenu *menuPtr; /* Menu in which to activate. */ - int index; /* Index of entry to activate, or - * -1 to deactivate all entries. */ -{ - register TkMenuEntry *mePtr; - int result = TCL_OK; - - if (menuPtr->active >= 0) { - mePtr = menuPtr->entries[menuPtr->active]; - - /* - * Don't change the state unless it's currently active (state - * might already have been changed to disabled). - */ - - if (mePtr->state == tkActiveUid) { - mePtr->state = tkNormalUid; - } - TkEventuallyRedrawMenu(menuPtr, menuPtr->entries[menuPtr->active]); - } - menuPtr->active = index; - if (index >= 0) { - mePtr = menuPtr->entries[index]; - mePtr->state = tkActiveUid; - TkEventuallyRedrawMenu(menuPtr, mePtr); - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * TkPostCommand -- - * - * Execute the postcommand for the given menu. - * - * Results: - * The return value is a standard Tcl result (errors can occur - * while the postcommands are being processed). - * - * Side effects: - * Since commands can get executed while this routine is being executed, - * the entire world can change. - * - *---------------------------------------------------------------------- - */ - -int -TkPostCommand(menuPtr) - TkMenu *menuPtr; -{ - int result; - - /* - * If there is a command for the menu, execute it. This - * may change the size of the menu, so be sure to recompute - * the menu's geometry if needed. - */ - - if (menuPtr->postCommand != NULL) { - result = TkCopyAndGlobalEval(menuPtr->interp, - menuPtr->postCommand); - if (result != TCL_OK) { - return result; - } - TkRecomputeMenu(menuPtr); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * CloneMenu -- - * - * Creates a child copy of the menu. It will be inserted into - * the menu's instance chain. All attributes and entry - * attributes will be duplicated. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Allocates storage. After the menu is created, any - * configuration done with this menu or any related one - * will be reflected in all of them. - * - *-------------------------------------------------------------- - */ - -static int -CloneMenu(menuPtr, newMenuName, newMenuTypeString) - TkMenu *menuPtr; /* The menu we are going to clone */ - char *newMenuName; /* The name to give the new menu */ - char *newMenuTypeString; /* What kind of menu is this, a normal menu - * a menubar, or a tearoff? */ -{ - int returnResult; - int menuType; - size_t length; - TkMenuReferences *menuRefPtr; - Tcl_Obj *commandObjPtr; - - if (newMenuTypeString == NULL) { - menuType = MASTER_MENU; - } else { - length = strlen(newMenuTypeString); - if (strncmp(newMenuTypeString, "normal", length) == 0) { - menuType = MASTER_MENU; - } else if (strncmp(newMenuTypeString, "tearoff", length) == 0) { - menuType = TEAROFF_MENU; - } else if (strncmp(newMenuTypeString, "menubar", length) == 0) { - menuType = MENUBAR; - } else { - Tcl_AppendResult(menuPtr->interp, - "bad menu type - must be normal, tearoff, or menubar", - (char *) NULL); - return TCL_ERROR; - } - } - - commandObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj("tkMenuDup", -1)); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(Tk_PathName(menuPtr->tkwin), -1)); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(newMenuName, -1)); - if ((newMenuTypeString == NULL) || (newMenuTypeString[0] == '\0')) { - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj("normal", -1)); - } else { - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(newMenuTypeString, -1)); - } - Tcl_IncrRefCount(commandObjPtr); - Tcl_Preserve((ClientData) menuPtr); - returnResult = Tcl_EvalObj(menuPtr->interp, commandObjPtr); - Tcl_DecrRefCount(commandObjPtr); - - /* - * Make sure the tcl command actually created the clone. - */ - - if ((returnResult == TCL_OK) && - ((menuRefPtr = TkFindMenuReferences(menuPtr->interp, newMenuName)) - != (TkMenuReferences *) NULL) - && (menuPtr->numEntries == menuRefPtr->menuPtr->numEntries)) { - TkMenu *newMenuPtr = menuRefPtr->menuPtr; - char *newArgv[3]; - int i, numElements; - - /* - * Now put this newly created menu into the parent menu's instance - * chain. - */ - - if (menuPtr->nextInstancePtr == NULL) { - menuPtr->nextInstancePtr = newMenuPtr; - newMenuPtr->masterMenuPtr = menuPtr->masterMenuPtr; - } else { - TkMenu *masterMenuPtr; - - masterMenuPtr = menuPtr->masterMenuPtr; - newMenuPtr->nextInstancePtr = masterMenuPtr->nextInstancePtr; - masterMenuPtr->nextInstancePtr = newMenuPtr; - newMenuPtr->masterMenuPtr = masterMenuPtr; - } - - /* - * Add the master menu's window to the bind tags for this window - * after this window's tag. This is so the user can bind to either - * this clone (which may not be easy to do) or the entire menu - * clone structure. - */ - - newArgv[0] = "bindtags"; - newArgv[1] = Tk_PathName(newMenuPtr->tkwin); - if (Tk_BindtagsCmd((ClientData)newMenuPtr->tkwin, - newMenuPtr->interp, 2, newArgv) == TCL_OK) { - char *windowName; - Tcl_Obj *bindingsPtr = - Tcl_NewStringObj(newMenuPtr->interp->result, -1); - Tcl_Obj *elementPtr; - - Tcl_ListObjLength(newMenuPtr->interp, bindingsPtr, &numElements); - for (i = 0; i < numElements; i++) { - Tcl_ListObjIndex(newMenuPtr->interp, bindingsPtr, i, - &elementPtr); - windowName = Tcl_GetStringFromObj(elementPtr, NULL); - if (strcmp(windowName, Tk_PathName(newMenuPtr->tkwin)) - == 0) { - Tcl_Obj *newElementPtr = Tcl_NewStringObj( - Tk_PathName(newMenuPtr->masterMenuPtr->tkwin), -1); - Tcl_ListObjReplace(menuPtr->interp, bindingsPtr, - i + 1, 0, 1, &newElementPtr); - newArgv[2] = Tcl_GetStringFromObj(bindingsPtr, NULL); - Tk_BindtagsCmd((ClientData)newMenuPtr->tkwin, - menuPtr->interp, 3, newArgv); - break; - } - } - Tcl_DecrRefCount(bindingsPtr); - } - Tcl_ResetResult(menuPtr->interp); - - /* - * Clone all of the cascade menus that this menu points to. - */ - - for (i = 0; i < menuPtr->numEntries; i++) { - char *newCascadeName; - TkMenuReferences *cascadeRefPtr; - TkMenu *oldCascadePtr; - - if ((menuPtr->entries[i]->type == CASCADE_ENTRY) - && (menuPtr->entries[i]->name != NULL)) { - cascadeRefPtr = - TkFindMenuReferences(menuPtr->interp, - menuPtr->entries[i]->name); - if ((cascadeRefPtr != NULL) && (cascadeRefPtr->menuPtr)) { - char *nameString; - - oldCascadePtr = cascadeRefPtr->menuPtr; - - nameString = Tk_PathName(newMenuPtr->tkwin); - newCascadeName = TkNewMenuName(menuPtr->interp, - nameString, oldCascadePtr); - CloneMenu(oldCascadePtr, newCascadeName, NULL); - - newArgv[0] = "-menu"; - newArgv[1] = newCascadeName; - ConfigureMenuEntry(newMenuPtr->entries[i], 2, newArgv, - TK_CONFIG_ARGV_ONLY); - ckfree(newCascadeName); - } - } - } - - returnResult = TCL_OK; - } else { - returnResult = TCL_ERROR; - } - Tcl_Release((ClientData) menuPtr); - return returnResult; -} - -/* - *---------------------------------------------------------------------- - * - * MenuDoYPosition -- - * - * Given arguments from an option command line, returns the Y position. - * - * Results: - * Returns TCL_OK or TCL_Error - * - * Side effects: - * yPosition is set to the Y-position of the menu entry. - * - *---------------------------------------------------------------------- - */ - -static int -MenuDoYPosition(interp, menuPtr, arg) - Tcl_Interp *interp; - TkMenu *menuPtr; - char *arg; -{ - int index; - - TkRecomputeMenu(menuPtr); - if (TkGetMenuIndex(interp, menuPtr, arg, 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - interp->result = "0"; - } else { - sprintf(interp->result, "%d", menuPtr->entries[index]->y); - } - return TCL_OK; - -error: - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * GetIndexFromCoords -- - * - * Given a string of the form "@int", return the menu item corresponding - * to int. - * - * Results: - * If int is a valid number, *indexPtr will be the number of the menuentry - * that is the correct height. If int is invaled, *indexPtr will be - * unchanged. Returns appropriate Tcl error number. - * - * Side effects: - * If int is invalid, interp's result will set to NULL. - * - *---------------------------------------------------------------------- - */ - -static int -GetIndexFromCoords(interp, menuPtr, string, indexPtr) - Tcl_Interp *interp; /* interp of menu */ - TkMenu *menuPtr; /* the menu we are searching */ - char *string; /* The @string we are parsing */ - int *indexPtr; /* The index of the item that matches */ -{ - int x, y, i; - char *p, *end; - - TkRecomputeMenu(menuPtr); - p = string + 1; - y = strtol(p, &end, 0); - if (end == p) { - goto error; - } - if (*end == ',') { - x = y; - p = end + 1; - y = strtol(p, &end, 0); - if (end == p) { - goto error; - } - } else { - x = menuPtr->borderWidth; - } - - for (i = 0; i < menuPtr->numEntries; i++) { - if ((x >= menuPtr->entries[i]->x) && (y >= menuPtr->entries[i]->y) - && (x < (menuPtr->entries[i]->x + menuPtr->entries[i]->width)) - && (y < (menuPtr->entries[i]->y - + menuPtr->entries[i]->height))) { - break; - } - } - if (i >= menuPtr->numEntries) { - /* i = menuPtr->numEntries - 1; */ - i = -1; - } - *indexPtr = i; - return TCL_OK; - - error: - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * RecursivelyDeleteMenu -- - * - * Deletes a menu and any cascades underneath it. Used for deleting - * instances when a menu is no longer being used as a menubar, - * for instance. - * - * Results: - * None. - * - * Side effects: - * Destroys the menu and all cascade menus underneath it. - * - *---------------------------------------------------------------------- - */ - -static void -RecursivelyDeleteMenu(menuPtr) - TkMenu *menuPtr; /* The menubar instance we are deleting */ -{ - int i; - TkMenuEntry *mePtr; - - for (i = 0; i < menuPtr->numEntries; i++) { - mePtr = menuPtr->entries[i]; - if ((mePtr->type == CASCADE_ENTRY) - && (mePtr->childMenuRefPtr != NULL) - && (mePtr->childMenuRefPtr->menuPtr != NULL)) { - RecursivelyDeleteMenu(mePtr->childMenuRefPtr->menuPtr); - } - } - Tk_DestroyWindow(menuPtr->tkwin); -} - -/* - *---------------------------------------------------------------------- - * - * TkNewMenuName -- - * - * Makes a new unique name for a cloned menu. Will be a child - * of oldName. - * - * Results: - * Returns a char * which has been allocated; caller must free. - * - * Side effects: - * Memory is allocated. - * - *---------------------------------------------------------------------- - */ - -char * -TkNewMenuName(interp, parentName, menuPtr) - Tcl_Interp *interp; /* The interp the new name has to live in.*/ - char *parentName; /* The prefix path of the new name. */ - TkMenu *menuPtr; /* The menu we are cloning. */ -{ - Tcl_DString resultDString; - Tcl_DString childDString; - char *destString; - int offset, i; - int doDot = parentName[strlen(parentName) - 1] != '.'; - Tcl_CmdInfo cmdInfo; - char *returnString; - Tcl_HashTable *nameTablePtr = NULL; - TkWindow *winPtr = (TkWindow *) menuPtr->tkwin; - if (winPtr->mainPtr != NULL) { - nameTablePtr = &(winPtr->mainPtr->nameTable); - } - - Tcl_DStringInit(&childDString); - Tcl_DStringAppend(&childDString, Tk_PathName(menuPtr->tkwin), -1); - for (destString = Tcl_DStringValue(&childDString); - *destString != '\0'; destString++) { - if (*destString == '.') { - *destString = '#'; - } - } - - offset = 0; - - for (i = 0; ; i++) { - if (i == 0) { - Tcl_DStringInit(&resultDString); - Tcl_DStringAppend(&resultDString, parentName, -1); - if (doDot) { - Tcl_DStringAppend(&resultDString, ".", -1); - } - Tcl_DStringAppend(&resultDString, - Tcl_DStringValue(&childDString), -1); - destString = Tcl_DStringValue(&resultDString); - } else { - if (i == 1) { - offset = Tcl_DStringLength(&resultDString); - Tcl_DStringSetLength(&resultDString, offset + 10); - destString = Tcl_DStringValue(&resultDString); - } - sprintf(destString + offset, "%d", i); - } - if ((Tcl_GetCommandInfo(interp, destString, &cmdInfo) == 0) - && ((nameTablePtr == NULL) - || (Tcl_FindHashEntry(nameTablePtr, destString) == NULL))) { - break; - } - } - returnString = ckalloc(strlen(destString) + 1); - strcpy(returnString, destString); - Tcl_DStringFree(&resultDString); - Tcl_DStringFree(&childDString); - return returnString; -} - -/* - *---------------------------------------------------------------------- - * - * TkSetWindowMenuBar -- - * - * Associates a menu with a window. Called by ConfigureFrame in - * in response to a "-menu .foo" configuration option for a top - * level. - * - * Results: - * None. - * - * Side effects: - * The old menu clones for the menubar are thrown away, and a - * handler is set up to allocate the new ones. - * - *---------------------------------------------------------------------- - */ -void -TkSetWindowMenuBar(interp, tkwin, oldMenuName, menuName) - Tcl_Interp *interp; /* The interpreter the toplevel lives in. */ - Tk_Window tkwin; /* The toplevel window */ - char *oldMenuName; /* The name of the menubar previously set in - * this toplevel. NULL means no menu was - * set previously. */ - char *menuName; /* The name of the new menubar that the - * toplevel needs to be set to. NULL means - * that their is no menu now. */ -{ - TkMenuTopLevelList *topLevelListPtr, *prevTopLevelPtr; - TkMenu *menuPtr; - TkMenuReferences *menuRefPtr; - - TkMenuInit(); - - /* - * Destroy the menubar instances of the old menu. Take this window - * out of the old menu's top level reference list. - */ - - if (oldMenuName != NULL) { - menuRefPtr = TkFindMenuReferences(interp, oldMenuName); - if (menuRefPtr != NULL) { - - /* - * Find the menubar instance that is to be removed. Destroy - * it and all of the cascades underneath it. - */ - - if (menuRefPtr->menuPtr != NULL) { - TkMenu *instancePtr; - - menuPtr = menuRefPtr->menuPtr; - - for (instancePtr = menuPtr->masterMenuPtr; - instancePtr != NULL; - instancePtr = instancePtr->nextInstancePtr) { - if (instancePtr->menuType == MENUBAR - && instancePtr->parentTopLevelPtr == tkwin) { - RecursivelyDeleteMenu(instancePtr); - break; - } - } - } - - /* - * Now we need to remove this toplevel from the list of toplevels - * that reference this menu. - */ - - for (topLevelListPtr = menuRefPtr->topLevelListPtr, - prevTopLevelPtr = NULL; - (topLevelListPtr != NULL) - && (topLevelListPtr->tkwin != tkwin); - prevTopLevelPtr = topLevelListPtr, - topLevelListPtr = topLevelListPtr->nextPtr) { - - /* - * Empty loop body. - */ - - } - - /* - * Now we have found the toplevel reference that matches the - * tkwin; remove this reference from the list. - */ - - if (topLevelListPtr != NULL) { - if (prevTopLevelPtr == NULL) { - menuRefPtr->topLevelListPtr = - menuRefPtr->topLevelListPtr->nextPtr; - } else { - prevTopLevelPtr->nextPtr = topLevelListPtr->nextPtr; - } - ckfree((char *) topLevelListPtr); - TkFreeMenuReferences(menuRefPtr); - } - } - } - - /* - * Now, add the clone references for the new menu. - */ - - if (menuName != NULL && menuName[0] != 0) { - TkMenu *menuBarPtr = NULL; - - menuRefPtr = TkCreateMenuReferences(interp, menuName); - - menuPtr = menuRefPtr->menuPtr; - if (menuPtr != NULL) { - char *cloneMenuName; - TkMenuReferences *cloneMenuRefPtr; - char *newArgv[4]; - - /* - * Clone the menu and all of the cascades underneath it. - */ - - cloneMenuName = TkNewMenuName(interp, Tk_PathName(tkwin), - menuPtr); - CloneMenu(menuPtr, cloneMenuName, "menubar"); - - cloneMenuRefPtr = TkFindMenuReferences(interp, cloneMenuName); - if ((cloneMenuRefPtr != NULL) - && (cloneMenuRefPtr->menuPtr != NULL)) { - cloneMenuRefPtr->menuPtr->parentTopLevelPtr = tkwin; - menuBarPtr = cloneMenuRefPtr->menuPtr; - newArgv[0] = "-cursor"; - newArgv[1] = ""; - ConfigureMenu(menuPtr->interp, cloneMenuRefPtr->menuPtr, - 2, newArgv, TK_CONFIG_ARGV_ONLY); - } - - TkpSetWindowMenuBar(tkwin, menuBarPtr); - - ckfree(cloneMenuName); - } else { - TkpSetWindowMenuBar(tkwin, NULL); - } - - - /* - * Add this window to the menu's list of windows that refer - * to this menu. - */ - - topLevelListPtr = (TkMenuTopLevelList *) - ckalloc(sizeof(TkMenuTopLevelList)); - topLevelListPtr->tkwin = tkwin; - topLevelListPtr->nextPtr = menuRefPtr->topLevelListPtr; - menuRefPtr->topLevelListPtr = topLevelListPtr; - } else { - TkpSetWindowMenuBar(tkwin, NULL); - } - TkpSetMainMenubar(interp, tkwin, menuName); -} - -/* - *---------------------------------------------------------------------- - * - * DestroyMenuHashTable -- - * - * Called when an interp is deleted and a menu hash table has - * been set in it. - * - * Results: - * None. - * - * Side effects: - * The hash table is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyMenuHashTable(clientData, interp) - ClientData clientData; /* The menu hash table we are destroying */ - Tcl_Interp *interp; /* The interpreter we are destroying */ -{ - Tcl_DeleteHashTable((Tcl_HashTable *) clientData); - ckfree((char *) clientData); -} - -/* - *---------------------------------------------------------------------- - * - * TkGetMenuHashTable -- - * - * For a given interp, give back the menu hash table that goes with - * it. If the hash table does not exist, it is created. - * - * Results: - * Returns a hash table pointer. - * - * Side effects: - * A new hash table is created if there were no table in the interp - * originally. - * - *---------------------------------------------------------------------- - */ - -Tcl_HashTable * -TkGetMenuHashTable(interp) - Tcl_Interp *interp; /* The interp we need the hash table in.*/ -{ - Tcl_HashTable *menuTablePtr; - - menuTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, MENU_HASH_KEY, - NULL); - if (menuTablePtr == NULL) { - menuTablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); - Tcl_InitHashTable(menuTablePtr, TCL_STRING_KEYS); - Tcl_SetAssocData(interp, MENU_HASH_KEY, DestroyMenuHashTable, - (ClientData) menuTablePtr); - } - return menuTablePtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkCreateMenuReferences -- - * - * Given a pathname, gives back a pointer to a TkMenuReferences structure. - * If a reference is not already in the hash table, one is created. - * - * Results: - * Returns a pointer to a menu reference structure. Should not - * be freed by calller; when a field of the reference is cleared, - * TkFreeMenuReferences should be called. - * - * Side effects: - * A new hash table entry is created if there were no references - * to the menu originally. - * - *---------------------------------------------------------------------- - */ - -TkMenuReferences * -TkCreateMenuReferences(interp, pathName) - Tcl_Interp *interp; - char *pathName; /* The path of the menu widget */ -{ - Tcl_HashEntry *hashEntryPtr; - TkMenuReferences *menuRefPtr; - int newEntry; - Tcl_HashTable *menuTablePtr = TkGetMenuHashTable(interp); - - hashEntryPtr = Tcl_CreateHashEntry(menuTablePtr, pathName, &newEntry); - if (newEntry) { - menuRefPtr = (TkMenuReferences *) ckalloc(sizeof(TkMenuReferences)); - menuRefPtr->menuPtr = NULL; - menuRefPtr->topLevelListPtr = NULL; - menuRefPtr->parentEntryPtr = NULL; - menuRefPtr->hashEntryPtr = hashEntryPtr; - Tcl_SetHashValue(hashEntryPtr, (char *) menuRefPtr); - } else { - menuRefPtr = (TkMenuReferences *) Tcl_GetHashValue(hashEntryPtr); - } - return menuRefPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkFindMenuReferences -- - * - * Given a pathname, gives back a pointer to the TkMenuReferences - * structure. - * - * Results: - * Returns a pointer to a menu reference structure. Should not - * be freed by calller; when a field of the reference is cleared, - * TkFreeMenuReferences should be called. Returns NULL if no reference - * with this pathname exists. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkMenuReferences * -TkFindMenuReferences(interp, pathName) - Tcl_Interp *interp; /* The interp the menu is living in. */ - char *pathName; /* The path of the menu widget */ -{ - Tcl_HashEntry *hashEntryPtr; - TkMenuReferences *menuRefPtr = NULL; - Tcl_HashTable *menuTablePtr; - - menuTablePtr = TkGetMenuHashTable(interp); - hashEntryPtr = Tcl_FindHashEntry(menuTablePtr, pathName); - if (hashEntryPtr != NULL) { - menuRefPtr = (TkMenuReferences *) Tcl_GetHashValue(hashEntryPtr); - } - return menuRefPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkFreeMenuReferences -- - * - * This is called after one of the fields in a menu reference - * is cleared. It cleans up the ref if it is now empty. - * - * Results: - * None. - * - * Side effects: - * If this is the last field to be cleared, the menu ref is - * taken out of the hash table. - * - *---------------------------------------------------------------------- - */ - -void -TkFreeMenuReferences(menuRefPtr) - TkMenuReferences *menuRefPtr; /* The menu reference to - * free */ -{ - if ((menuRefPtr->menuPtr == NULL) - && (menuRefPtr->parentEntryPtr == NULL) - && (menuRefPtr->topLevelListPtr == NULL)) { - Tcl_DeleteHashEntry(menuRefPtr->hashEntryPtr); - ckfree((char *) menuRefPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * DeleteMenuCloneEntries -- - * - * For every clone in this clone chain, delete the menu entries - * given by the parameters. - * - * Results: - * None. - * - * Side effects: - * The appropriate entries are deleted from all clones of this menu. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteMenuCloneEntries(menuPtr, first, last) - TkMenu *menuPtr; /* the menu the command was issued with */ - int first; /* the zero-based first entry in the set - * of entries to delete. */ - int last; /* the zero-based last entry */ -{ - - TkMenu *menuListPtr; - int numDeleted, i; - - numDeleted = last + 1 - first; - for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; - menuListPtr = menuListPtr->nextInstancePtr) { - for (i = last; i >= first; i--) { - Tcl_EventuallyFree((ClientData) menuListPtr->entries[i], - DestroyMenuEntry); - } - for (i = last + 1; i < menuListPtr->numEntries; i++) { - menuListPtr->entries[i - numDeleted] = menuListPtr->entries[i]; - menuListPtr->entries[i - numDeleted]->index = i; - } - menuListPtr->numEntries -= numDeleted; - if (menuListPtr->numEntries == 0) { - ckfree((char *) menuListPtr->entries); - menuListPtr->entries = NULL; - } - if ((menuListPtr->active >= first) - && (menuListPtr->active <= last)) { - menuListPtr->active = -1; - } else if (menuListPtr->active > last) { - menuListPtr->active -= numDeleted; - } - TkEventuallyRecomputeMenu(menuListPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuInit -- - * - * Sets up the hash tables and the variables used by the menu package. - * - * Results: - * None. - * - * Side effects: - * lastMenuID gets initialized, and the parent hash and the command hash - * are allocated. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuInit() -{ - if (!menusInitialized) { - TkpMenuInit(); - menusInitialized = 1; - } -} diff --git a/generic/tkMenu.h b/generic/tkMenu.h deleted file mode 100644 index c6fd3fe..0000000 --- a/generic/tkMenu.h +++ /dev/null @@ -1,549 +0,0 @@ -/* - * tkMenu.h -- - * - * Declarations shared among all of the files that implement menu widgets. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMenu.h,v 1.4 1998/09/14 18:23:14 stanton Exp $ - */ - -#ifndef _TKMENU -#define _TKMENU - -#ifndef _TK -#include "tk.h" -#endif - -#ifndef _TKINT -#include "tkInt.h" -#endif - -#ifndef _DEFAULT -#include "default.h" -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * Dummy types used by the platform menu code. - */ - -typedef struct TkMenuPlatformData_ *TkMenuPlatformData; -typedef struct TkMenuPlatformEntryData_ *TkMenuPlatformEntryData; - -/* - * One of the following data structures is kept for each entry of each - * menu managed by this file: - */ - -typedef struct TkMenuEntry { - int type; /* Type of menu entry; see below for - * valid types. */ - struct TkMenu *menuPtr; /* Menu with which this entry is associated. */ - char *label; /* Main text label displayed in entry (NULL - * if no label). Malloc'ed. */ - int labelLength; /* Number of non-NULL characters in label. */ - Tk_Uid state; /* State of button for display purposes: - * normal, active, or disabled. */ - int underline; /* Index of character to underline. */ - Pixmap bitmap; /* Bitmap to display in menu entry, or None. - * If not None then label is ignored. */ - char *imageString; /* Name of image to display (malloc'ed), or - * NULL. If non-NULL, bitmap, text, and - * textVarName are ignored. */ - Tk_Image image; /* Image to display in menu entry, or NULL if - * none. */ - char *selectImageString; /* Name of image to display when selected - * (malloc'ed), or NULL. */ - Tk_Image selectImage; /* Image to display in entry when selected, - * or NULL if none. Ignored if image is - * NULL. */ - char *accel; /* Accelerator string displayed at right - * of menu entry. NULL means no such - * accelerator. Malloc'ed. */ - int accelLength; /* Number of non-NULL characters in - * accelerator. */ - int indicatorOn; /* True means draw indicator, false means - * don't draw it. */ - /* - * Display attributes - */ - - Tk_3DBorder border; /* Structure used to draw background for - * entry. NULL means use overall border - * for menu. */ - XColor *fg; /* Foreground color to use for entry. NULL - * means use foreground color from menu. */ - Tk_3DBorder activeBorder; /* Used to draw background and border when - * element is active. NULL means use - * activeBorder from menu. */ - XColor *activeFg; /* Foreground color to use when entry is - * active. NULL means use active foreground - * from menu. */ - XColor *indicatorFg; /* Color for indicators in radio and check - * button entries. NULL means use indicatorFg - * GC from menu. */ - Tk_Font tkfont; /* Text font for menu entries. NULL means - * use overall font for menu. */ - int columnBreak; /* If this is 0, this item appears below - * the item in front of it. If this is - * 1, this item starts a new column. */ - int hideMargin; /* If this is 0, then the item has enough - * margin to accomodate a standard check - * mark and a default right margin. If this - * is 1, then the item has no such margins. - * and checkbuttons and radiobuttons with - * this set will have a rectangle drawn - * in the indicator around the item if - * the item is checked. - * This is useful palette menus.*/ - int indicatorSpace; /* The width of the indicator space for this - * entry. - */ - int labelWidth; /* Number of pixels to allow for displaying - * labels in menu entries. */ - - /* - * Information used to implement this entry's action: - */ - - char *command; /* Command to invoke when entry is invoked. - * Malloc'ed. */ - char *name; /* Name of variable (for check buttons and - * radio buttons) or menu (for cascade - * entries). Malloc'ed.*/ - char *onValue; /* Value to store in variable when selected - * (only for radio and check buttons). - * Malloc'ed. */ - char *offValue; /* Value to store in variable when not - * selected (only for check buttons). - * Malloc'ed. */ - - /* - * Information used for drawing this menu entry. - */ - - int width; /* Number of pixels occupied by entry in - * horizontal dimension. Not used except - * in menubars. The width of norma menus - * is dependent on the rest of the menu. */ - int x; /* X-coordinate of leftmost pixel in entry */ - int height; /* Number of pixels occupied by entry in - * vertical dimension, including raised - * border drawn around entry when active. */ - int y; /* Y-coordinate of topmost pixel in entry. */ - GC textGC; /* GC for drawing text in entry. NULL means - * use overall textGC for menu. */ - GC activeGC; /* GC for drawing text in entry when active. - * NULL means use overall activeGC for - * menu. */ - GC disabledGC; /* Used to produce disabled effect for entry. - * NULL means use overall disabledGC from - * menu structure. See comments for - * disabledFg in menu structure for more - * information. */ - GC indicatorGC; /* For drawing indicators. None means use - * GC from menu. */ - - /* - * Miscellaneous fields. - */ - - int entryFlags; /* Various flags. See below for - definitions. */ - int index; /* Need to know which index we are. This - * is zero-based. This is the top-left entry - * of the menu. */ - - /* - * Bookeeping for master menus and cascade menus. - */ - - struct TkMenuReferences *childMenuRefPtr; - /* A pointer to the hash table entry for - * the child menu. Stored here when the menu - * entry is configured so that a hash lookup - * is not necessary later.*/ - struct TkMenuEntry *nextCascadePtr; - /* The next cascade entry that is a parent of - * this entry's child cascade menu. NULL - * end of list, this is not a cascade entry, - * or the menu that this entry point to - * does not yet exist. */ - TkMenuPlatformEntryData platformEntryData; - /* The data for the specific type of menu. - * Depends on platform and menu type what - * kind of options are in this structure. - */ -} TkMenuEntry; - -/* - * Flag values defined for menu entries: - * - * ENTRY_SELECTED: Non-zero means this is a radio or check - * button and that it should be drawn in - * the "selected" state. - * ENTRY_NEEDS_REDISPLAY: Non-zero means the entry should be redisplayed. - * ENTRY_LAST_COLUMN: Used by the drawing code. If the entry is in the - * last column, the space to its right needs to - * be filled. - * ENTRY_PLATFORM_FLAG1 - 4 These flags are reserved for use by the - * platform-dependent implementation of menus - * and should not be used by anything else. - */ - -#define ENTRY_SELECTED 1 -#define ENTRY_NEEDS_REDISPLAY 2 -#define ENTRY_LAST_COLUMN 4 -#define ENTRY_PLATFORM_FLAG1 (1 << 30) -#define ENTRY_PLATFORM_FLAG2 (1 << 29) -#define ENTRY_PLATFORM_FLAG3 (1 << 28) -#define ENTRY_PLATFORM_FLAG4 (1 << 27) - -/* - * Types defined for MenuEntries: - */ - -#define COMMAND_ENTRY 0 -#define SEPARATOR_ENTRY 1 -#define CHECK_BUTTON_ENTRY 2 -#define RADIO_BUTTON_ENTRY 3 -#define CASCADE_ENTRY 4 -#define TEAROFF_ENTRY 5 - -/* - * Mask bits for above types: - */ - -#define COMMAND_MASK TK_CONFIG_USER_BIT -#define SEPARATOR_MASK (TK_CONFIG_USER_BIT << 1) -#define CHECK_BUTTON_MASK (TK_CONFIG_USER_BIT << 2) -#define RADIO_BUTTON_MASK (TK_CONFIG_USER_BIT << 3) -#define CASCADE_MASK (TK_CONFIG_USER_BIT << 4) -#define TEAROFF_MASK (TK_CONFIG_USER_BIT << 5) -#define ALL_MASK (COMMAND_MASK | SEPARATOR_MASK \ - | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | CASCADE_MASK | TEAROFF_MASK) - -/* - * A data structure of the following type is kept for each - * menu widget: - */ - -typedef struct TkMenu { - Tk_Window tkwin; /* Window that embodies the pane. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Needed, among - * other things, so that resources can be - * freed up even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with menu. */ - Tcl_Command widgetCmd; /* Token for menu's widget command. */ - TkMenuEntry **entries; /* Array of pointers to all the entries - * in the menu. NULL means no entries. */ - int numEntries; /* Number of elements in entries. */ - int active; /* Index of active entry. -1 means - * nothing active. */ - int menuType; /* MASTER_MENU, TEAROFF_MENU, or MENUBAR. - * See below for definitions. */ - char *menuTypeName; /* Used to control whether created tkwin - * is a toplevel or not. "normal", "menubar", - * or "toplevel" */ - - /* - * Information used when displaying widget: - */ - - Tk_3DBorder border; /* Structure used to draw 3-D - * border and background for menu. */ - int borderWidth; /* Width of border around whole menu. */ - Tk_3DBorder activeBorder; /* Used to draw background and border for - * active element (if any). */ - int activeBorderWidth; /* Width of border around active element. */ - int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ - Tk_Font tkfont; /* Text font for menu entries. */ - XColor *fg; /* Foreground color for entries. */ - XColor *disabledFg; /* Foreground color when disabled. NULL - * means use normalFg with a 50% stipple - * instead. */ - XColor *activeFg; /* Foreground color for active entry. */ - XColor *indicatorFg; /* Color for indicators in radio and check - * button entries. */ - Pixmap gray; /* Bitmap for drawing disabled entries in - * a stippled fashion. None means not - * allocated yet. */ - GC textGC; /* GC for drawing text and other features - * of menu entries. */ - GC disabledGC; /* Used to produce disabled effect. If - * disabledFg isn't NULL, this GC is used to - * draw text and icons for disabled entries. - * Otherwise text and icons are drawn with - * normalGC and this GC is used to stipple - * background across them. */ - GC activeGC; /* GC for drawing active entry. */ - GC indicatorGC; /* For drawing indicators. */ - GC disabledImageGC; /* Used for drawing disabled images. They - * have to be stippled. This is created - * when the image is about to be drawn the - * first time. */ - - /* - * Information about geometry of menu. - */ - - int totalWidth; /* Width of entire menu */ - int totalHeight; /* Height of entire menu */ - - /* - * Miscellaneous information: - */ - - int tearOff; /* 1 means this menu can be torn off. On some - * platforms, the user can drag an outline - * of the menu by just dragging outside of - * the menu, and the tearoff is created where - * the mouse is released. On others, an - * indicator (such as a dashed stripe) is - * drawn, and when the menu is selected, the - * tearoff is created. */ - char *title; /* The title to use when this menu is torn - * off. If this is NULL, a default scheme - * will be used to generate a title for - * tearoff. */ - char *tearOffCommand; /* If non-NULL, points to a command to - * run whenever the menu is torn-off. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *postCommand; /* Used to detect cycles in cascade hierarchy - * trees when preprocessing postcommands - * on some platforms. See PostMenu for - * more details. */ - int postCommandGeneration; /* Need to do pre-invocation post command - * traversal */ - int menuFlags; /* Flags for use by X; see below for - definition */ - TkMenuEntry *postedCascade; /* Points to menu entry for cascaded submenu - * that is currently posted or NULL if no - * submenu posted. */ - struct TkMenu *nextInstancePtr; - /* The next instance of this menu in the - * chain. */ - struct TkMenu *masterMenuPtr; - /* A pointer to the original menu for this - * clone chain. Points back to this structure - * if this menu is a master menu. */ - Tk_Window parentTopLevelPtr;/* If this menu is a menubar, this is the - * toplevel that owns the menu. Only applicable - * for menubar clones. - */ - struct TkMenuReferences *menuRefPtr; - /* Each menu is hashed into a table with the - * name of the menu's window as the key. - * The information in this hash table includes - * a pointer to the menu (so that cascades - * can find this menu), a pointer to the - * list of toplevel widgets that have this - * menu as its menubar, and a list of menu - * entries that have this menu specified - * as a cascade. */ - TkMenuPlatformData platformData; - /* The data for the specific type of menu. - * Depends on platform and menu type what - * kind of options are in this structure. - */ -} TkMenu; - -/* - * When the toplevel configure -menu command is executed, the menu may not - * exist yet. We need to keep a linked list of windows that reference - * a particular menu. - */ - -typedef struct TkMenuTopLevelList { - struct TkMenuTopLevelList *nextPtr; - /* The next window in the list */ - Tk_Window tkwin; /* The window that has this menu as its - * menubar. */ -} TkMenuTopLevelList; - -/* - * The following structure is used to keep track of things which - * reference a menu. It is created when: - * - a menu is created. - * - a cascade entry is added to a menu with a non-null name - * - the "-menu" configuration option is used on a toplevel widget - * with a non-null parameter. - * - * One of these three fields must be non-NULL, but any of the fields may - * be NULL. This structure makes it easy to determine whether or not - * anything like recalculating platform data or geometry is necessary - * when one of the three actions above is performed. - */ - -typedef struct TkMenuReferences { - struct TkMenu *menuPtr; /* The menu data structure. This is NULL - * if the menu does not exist. */ - TkMenuTopLevelList *topLevelListPtr; - /* First in the list of all toplevels that - * have this menu as its menubar. NULL if no - * toplevel widgets have this menu as its - * menubar. */ - TkMenuEntry *parentEntryPtr;/* First in the list of all cascade menu - * entries that have this menu as their child. - * NULL means no cascade entries. */ - Tcl_HashEntry *hashEntryPtr;/* This is needed because the pathname of the - * window (which is what we hash on) may not - * be around when we are deleting. - */ -} TkMenuReferences; - -/* - * Flag bits for menus: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * RESIZE_PENDING: Non-zero means a call to ComputeMenuGeometry - * has already been scheduled. - * MENU_DELETION_PENDING Non-zero means that we are currently destroying - * this menu. This is useful when we are in the - * middle of cleaning this master menu's chain of - * menus up when TkDestroyMenu was called again on - * this menu (via a destroy binding or somesuch). - * MENU_PLATFORM_FLAG1... Reserved for use by the platform-specific menu - * code. - */ - -#define REDRAW_PENDING 1 -#define RESIZE_PENDING 2 -#define MENU_DELETION_PENDING 4 -#define MENU_PLATFORM_FLAG1 (1 << 30) -#define MENU_PLATFORM_FLAG2 (1 << 29) -#define MENU_PLATFORM_FLAG3 (1 << 28) - -/* - * Each menu created by the user is a MASTER_MENU. When a menu is torn off, - * a TEAROFF_MENU instance is created. When a menu is assigned to a toplevel - * as a menu bar, a MENUBAR instance is created. All instances have the same - * configuration information. If the master instance is deleted, all instances - * are deleted. If one of the other instances is deleted, only that instance - * is deleted. - */ - -#define UNKNOWN_TYPE -1 -#define MASTER_MENU 0 -#define TEAROFF_MENU 1 -#define MENUBAR 2 - -/* - * Various geometry definitions: - */ - -#define CASCADE_ARROW_HEIGHT 10 -#define CASCADE_ARROW_WIDTH 8 -#define DECORATION_BORDER_WIDTH 2 - -/* - * Configuration specs. Needed for platform-specific default initializations. - */ - -EXTERN Tk_ConfigSpec tkMenuEntryConfigSpecs[]; -EXTERN Tk_ConfigSpec tkMenuConfigSpecs[]; - -/* - * Menu-related procedures that are shared among Tk modules but not exported - * to the outside world: - */ - -EXTERN int TkActivateMenuEntry _ANSI_ARGS_((TkMenu *menuPtr, - int index)); -EXTERN void TkBindMenu _ANSI_ARGS_(( - Tk_Window tkwin, TkMenu *menuPtr)); -EXTERN TkMenuReferences * - TkCreateMenuReferences _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName)); -EXTERN void TkDestroyMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkEventuallyRecomputeMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkEventuallyRedrawMenu _ANSI_ARGS_(( - TkMenu *menuPtr, TkMenuEntry *mePtr)); -EXTERN TkMenuReferences * - TkFindMenuReferences _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName)); -EXTERN void TkFreeMenuReferences _ANSI_ARGS_(( - TkMenuReferences *menuRefPtr)); -EXTERN Tcl_HashTable * TkGetMenuHashTable _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN int TkGetMenuIndex _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *string, int lastOK, - int *indexPtr)); -EXTERN void TkMenuInitializeDrawingFields _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkMenuInitializeEntryDrawingFields _ANSI_ARGS_(( - TkMenuEntry *mePtr)); -EXTERN int TkInvokeMenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, int index)); -EXTERN void TkMenuConfigureDrawOptions _ANSI_ARGS_(( - TkMenu *menuPtr)); -EXTERN int TkMenuConfigureEntryDrawOptions _ANSI_ARGS_(( - TkMenuEntry *mePtr, int index)); -EXTERN void TkMenuFreeDrawOptions _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkMenuEntryFreeDrawOptions _ANSI_ARGS_(( - TkMenuEntry *mePtr)); -EXTERN void TkMenuEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -EXTERN void TkMenuImageProc _ANSI_ARGS_(( - ClientData clientData, int x, int y, int width, - int height, int imgWidth, int imgHeight)); -EXTERN void TkMenuInit _ANSI_ARGS_((void)); -EXTERN void TkMenuSelectImageProc _ANSI_ARGS_ - ((ClientData clientData, int x, int y, - int width, int height, int imgWidth, - int imgHeight)); -EXTERN char * TkNewMenuName _ANSI_ARGS_((Tcl_Interp *interp, - char *parentName, TkMenu *menuPtr)); -EXTERN int TkPostCommand _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN int TkPostSubmenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, TkMenuEntry *mePtr)); -EXTERN int TkPostTearoffMenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, int x, int y)); -EXTERN int TkPreprocessMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkRecomputeMenu _ANSI_ARGS_((TkMenu *menuPtr)); - -/* - * These routines are the platform-dependent routines called by the - * common code. - */ - -EXTERN void TkpComputeMenubarGeometry _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkpComputeStandardMenuGeometry _ANSI_ARGS_ - ((TkMenu *menuPtr)); -EXTERN int TkpConfigureMenuEntry - _ANSI_ARGS_((TkMenuEntry *mePtr)); -EXTERN void TkpDestroyMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkpDestroyMenuEntry - _ANSI_ARGS_((TkMenuEntry *mEntryPtr)); -EXTERN void TkpDrawMenuEntry _ANSI_ARGS_((TkMenuEntry *mePtr, - Drawable d, Tk_Font tkfont, - CONST Tk_FontMetrics *menuMetricsPtr, int x, - int y, int width, int height, int strictMotif, - int drawArrow)); -EXTERN void TkpMenuInit _ANSI_ARGS_((void)); -EXTERN int TkpMenuNewEntry _ANSI_ARGS_((TkMenuEntry *mePtr)); -EXTERN int TkpNewMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN int TkpPostMenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, int x, int y)); -EXTERN void TkpSetWindowMenuBar _ANSI_ARGS_((Tk_Window tkwin, - TkMenu *menuPtr)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKMENU */ - diff --git a/generic/tkMenuDraw.c b/generic/tkMenuDraw.c deleted file mode 100644 index c08e902..0000000 --- a/generic/tkMenuDraw.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * tkMenuDraw.c -- - * - * This module implements the platform-independent drawing and - * geometry calculations of menu widgets. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMenuDraw.c,v 1.2 1998/09/14 18:23:14 stanton Exp $ - */ - -#include "tkMenu.h" - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void AdjustMenuCoords _ANSI_ARGS_ ((TkMenu *menuPtr, - TkMenuEntry *mePtr, int *xPtr, int *yPtr, - char *string)); -static void ComputeMenuGeometry _ANSI_ARGS_(( - ClientData clientData)); -static void DisplayMenu _ANSI_ARGS_((ClientData clientData)); - -/* - *---------------------------------------------------------------------- - * - * TkMenuInitializeDrawingFields -- - * - * Fills in drawing fields of a new menu. Called when new menu is - * created by Tk_MenuCmd. - * - * Results: - * None. - * - * Side effects: - * menuPtr fields are initialized. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuInitializeDrawingFields(menuPtr) - TkMenu *menuPtr; /* The menu we are initializing. */ -{ - menuPtr->textGC = None; - menuPtr->gray = None; - menuPtr->disabledGC = None; - menuPtr->activeGC = None; - menuPtr->indicatorGC = None; - menuPtr->disabledImageGC = None; - menuPtr->totalWidth = menuPtr->totalHeight = 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuInitializeEntryDrawingFields -- - * - * Fills in drawing fields of a new menu entry. Called when an - * entry is created. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuInitializeEntryDrawingFields(mePtr) - TkMenuEntry *mePtr; /* The menu we are initializing. */ -{ - mePtr->width = 0; - mePtr->height = 0; - mePtr->x = 0; - mePtr->y = 0; - mePtr->indicatorSpace = 0; - mePtr->labelWidth = 0; - mePtr->textGC = None; - mePtr->activeGC = None; - mePtr->disabledGC = None; - mePtr->indicatorGC = None; -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuFreeDrawOptions -- - * - * Frees up any structures allocated for the drawing of a menu. - * Called when menu is deleted. - * - * Results: - * None. - * - * Side effects: - * Storage is released. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuFreeDrawOptions(menuPtr) - TkMenu *menuPtr; -{ - if (menuPtr->textGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->textGC); - } - if (menuPtr->disabledImageGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC); - } - if (menuPtr->gray != None) { - Tk_FreeBitmap(menuPtr->display, menuPtr->gray); - } - if (menuPtr->disabledGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->disabledGC); - } - if (menuPtr->activeGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->activeGC); - } - if (menuPtr->indicatorGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuEntryFreeDrawOptions -- - * - * Frees up drawing structures for a menu entry. Called when - * menu entry is freed. - * - * RESULTS: - * None. - * - * Side effects: - * Storage is freed. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuEntryFreeDrawOptions(mePtr) - TkMenuEntry *mePtr; -{ - if (mePtr->textGC != None) { - Tk_FreeGC(mePtr->menuPtr->display, mePtr->textGC); - } - if (mePtr->disabledGC != None) { - Tk_FreeGC(mePtr->menuPtr->display, mePtr->disabledGC); - } - if (mePtr->activeGC != None) { - Tk_FreeGC(mePtr->menuPtr->display, mePtr->activeGC); - } - if (mePtr->indicatorGC != None) { - Tk_FreeGC(mePtr->menuPtr->display, mePtr->indicatorGC); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuConfigureDrawOptions -- - * - * Sets the menu's drawing attributes in preparation for drawing - * the menu. - * - * RESULTS: - * None. - * - * Side effects: - * Storage is allocated. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuConfigureDrawOptions(menuPtr) - TkMenu *menuPtr; /* The menu we are configuring. */ -{ - XGCValues gcValues; - GC newGC; - unsigned long mask; - - /* - * A few options need special processing, such as setting the - * background from a 3-D border, or filling in complicated - * defaults that couldn't be specified to Tk_ConfigureWidget. - */ - - Tk_SetBackgroundFromBorder(menuPtr->tkwin, menuPtr->border); - - gcValues.font = Tk_FontId(menuPtr->tkfont); - gcValues.foreground = menuPtr->fg->pixel; - gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel; - newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues); - if (menuPtr->textGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->textGC); - } - menuPtr->textGC = newGC; - - gcValues.font = Tk_FontId(menuPtr->tkfont); - gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel; - if (menuPtr->disabledFg != NULL) { - gcValues.foreground = menuPtr->disabledFg->pixel; - mask = GCForeground|GCBackground|GCFont; - } else { - gcValues.foreground = gcValues.background; - mask = GCForeground; - if (menuPtr->gray == None) { - menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin, - Tk_GetUid("gray50")); - } - if (menuPtr->gray != None) { - gcValues.fill_style = FillStippled; - gcValues.stipple = menuPtr->gray; - mask = GCForeground|GCFillStyle|GCStipple; - } - } - newGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues); - if (menuPtr->disabledGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->disabledGC); - } - menuPtr->disabledGC = newGC; - - gcValues.foreground = Tk_3DBorderColor(menuPtr->border)->pixel; - if (menuPtr->gray == None) { - menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin, - Tk_GetUid("gray50")); - } - if (menuPtr->gray != None) { - gcValues.fill_style = FillStippled; - gcValues.stipple = menuPtr->gray; - newGC = Tk_GetGC(menuPtr->tkwin, - GCForeground|GCFillStyle|GCStipple, &gcValues); - } - if (menuPtr->disabledImageGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC); - } - menuPtr->disabledImageGC = newGC; - - gcValues.font = Tk_FontId(menuPtr->tkfont); - gcValues.foreground = menuPtr->activeFg->pixel; - gcValues.background = - Tk_3DBorderColor(menuPtr->activeBorder)->pixel; - newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues); - if (menuPtr->activeGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->activeGC); - } - menuPtr->activeGC = newGC; - - gcValues.foreground = menuPtr->indicatorFg->pixel; - gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel; - newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues); - if (menuPtr->indicatorGC != None) { - Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC); - } - menuPtr->indicatorGC = newGC; -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuConfigureEntryDrawOptions -- - * - * Calculates any entry-specific draw options for the given menu - * entry. - * - * Results: - * Returns a standard Tcl error. - * - * Side effects: - * Storage may be allocated. - * - *---------------------------------------------------------------------- - */ - -int -TkMenuConfigureEntryDrawOptions(mePtr, index) - TkMenuEntry *mePtr; - int index; -{ - - XGCValues gcValues; - GC newGC, newActiveGC, newDisabledGC, newIndicatorGC; - unsigned long mask; - Tk_Font tkfont; - TkMenu *menuPtr = mePtr->menuPtr; - - tkfont = (mePtr->tkfont == NULL) ? menuPtr->tkfont : mePtr->tkfont; - - if (mePtr->state == tkActiveUid) { - if (index != menuPtr->active) { - TkActivateMenuEntry(menuPtr, index); - } - } else { - if (index == menuPtr->active) { - TkActivateMenuEntry(menuPtr, -1); - } - if ((mePtr->state != tkNormalUid) - && (mePtr->state != tkDisabledUid)) { - Tcl_AppendResult(menuPtr->interp, "bad state value \"", - mePtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - mePtr->state = tkNormalUid; - return TCL_ERROR; - } - } - - if ((mePtr->tkfont != NULL) - || (mePtr->border != NULL) - || (mePtr->fg != NULL) - || (mePtr->activeBorder != NULL) - || (mePtr->activeFg != NULL) - || (mePtr->indicatorFg != NULL)) { - gcValues.foreground = (mePtr->fg != NULL) - ? mePtr->fg->pixel - : menuPtr->fg->pixel; - gcValues.background = Tk_3DBorderColor( - (mePtr->border != NULL) - ? mePtr->border - : menuPtr->border) - ->pixel; - - gcValues.font = Tk_FontId(tkfont); - - /* - * Note: disable GraphicsExpose events; we know there won't be - * obscured areas when copying from an off-screen pixmap to the - * screen and this gets rid of unnecessary events. - */ - - gcValues.graphics_exposures = False; - newGC = Tk_GetGC(menuPtr->tkwin, - GCForeground|GCBackground|GCFont|GCGraphicsExposures, - &gcValues); - - if (mePtr->indicatorFg != NULL) { - gcValues.foreground = mePtr->indicatorFg->pixel; - } else if (menuPtr->indicatorFg != NULL) { - gcValues.foreground = menuPtr->indicatorFg->pixel; - } - newIndicatorGC = Tk_GetGC(menuPtr->tkwin, - GCForeground|GCBackground|GCGraphicsExposures, - &gcValues); - - if ((menuPtr->disabledFg != NULL) || (mePtr->image != NULL)) { - gcValues.foreground = menuPtr->disabledFg->pixel; - mask = GCForeground|GCBackground|GCFont|GCGraphicsExposures; - } else { - gcValues.foreground = gcValues.background; - gcValues.fill_style = FillStippled; - gcValues.stipple = menuPtr->gray; - mask = GCForeground|GCFillStyle|GCStipple; - } - newDisabledGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues); - - gcValues.foreground = (mePtr->activeFg != NULL) - ? mePtr->activeFg->pixel - : menuPtr->activeFg->pixel; - gcValues.background = Tk_3DBorderColor( - (mePtr->activeBorder != NULL) - ? mePtr->activeBorder - : menuPtr->activeBorder)->pixel; - newActiveGC = Tk_GetGC(menuPtr->tkwin, - GCForeground|GCBackground|GCFont|GCGraphicsExposures, - &gcValues); - } else { - newGC = None; - newActiveGC = None; - newDisabledGC = None; - newIndicatorGC = None; - } - if (mePtr->textGC != None) { - Tk_FreeGC(menuPtr->display, mePtr->textGC); - } - mePtr->textGC = newGC; - if (mePtr->activeGC != None) { - Tk_FreeGC(menuPtr->display, mePtr->activeGC); - } - mePtr->activeGC = newActiveGC; - if (mePtr->disabledGC != None) { - Tk_FreeGC(menuPtr->display, mePtr->disabledGC); - } - mePtr->disabledGC = newDisabledGC; - if (mePtr->indicatorGC != None) { - Tk_FreeGC(menuPtr->display, mePtr->indicatorGC); - } - mePtr->indicatorGC = newIndicatorGC; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkEventuallyRecomputeMenu -- - * - * Tells Tcl to redo the geometry because this menu has changed. - * - * Results: - * None. - * - * Side effects: - * Menu geometry is recomputed at idle time, and the menu will be - * redisplayed. - * - *---------------------------------------------------------------------- - */ - -void -TkEventuallyRecomputeMenu(menuPtr) - TkMenu *menuPtr; -{ - if (!(menuPtr->menuFlags & RESIZE_PENDING)) { - menuPtr->menuFlags |= RESIZE_PENDING; - Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkRecomputeMenu -- - * - * Tells Tcl to redo the geometry because this menu has changed. - * Does it now; removes any ComputeMenuGeometries from the idler. - * - * Results: - * None. - * - * Side effects: - * Menu geometry is immediately reconfigured. - * - *---------------------------------------------------------------------- - */ - -void -TkRecomputeMenu(menuPtr) - TkMenu *menuPtr; -{ - if (menuPtr->menuFlags & RESIZE_PENDING) { - Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr); - ComputeMenuGeometry((ClientData) menuPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkEventuallyRedrawMenu -- - * - * Arrange for an entry of a menu, or the whole menu, to be - * redisplayed at some point in the future. - * - * Results: - * None. - * - * Side effects: - * A when-idle hander is scheduled to do the redisplay, if there - * isn't one already scheduled. - * - *---------------------------------------------------------------------- - */ - -void -TkEventuallyRedrawMenu(menuPtr, mePtr) - register TkMenu *menuPtr; /* Information about menu to redraw. */ - register TkMenuEntry *mePtr; /* Entry to redraw. NULL means redraw - * all the entries in the menu. */ -{ - int i; - - if (menuPtr->tkwin == NULL) { - return; - } - if (mePtr != NULL) { - mePtr->entryFlags |= ENTRY_NEEDS_REDISPLAY; - } else { - for (i = 0; i < menuPtr->numEntries; i++) { - menuPtr->entries[i]->entryFlags |= ENTRY_NEEDS_REDISPLAY; - } - } - if (!Tk_IsMapped(menuPtr->tkwin) - || (menuPtr->menuFlags & REDRAW_PENDING)) { - return; - } - Tcl_DoWhenIdle(DisplayMenu, (ClientData) menuPtr); - menuPtr->menuFlags |= REDRAW_PENDING; -} - -/* - *-------------------------------------------------------------- - * - * ComputeMenuGeometry -- - * - * This procedure is invoked to recompute the size and - * layout of a menu. It is called as a when-idle handler so - * that it only gets done once, even if a group of changes is - * made to the menu. - * - * Results: - * None. - * - * Side effects: - * Fields of menu entries are changed to reflect their - * current positions, and the size of the menu window - * itself may be changed. - * - *-------------------------------------------------------------- - */ - -static void -ComputeMenuGeometry(clientData) - ClientData clientData; /* Structure describing menu. */ -{ - TkMenu *menuPtr = (TkMenu *) clientData; - - if (menuPtr->tkwin == NULL) { - return; - } - - if (menuPtr->menuType == MENUBAR) { - TkpComputeMenubarGeometry(menuPtr); - } else { - TkpComputeStandardMenuGeometry(menuPtr); - } - - if ((menuPtr->totalWidth != Tk_ReqWidth(menuPtr->tkwin)) || - (menuPtr->totalHeight != Tk_ReqHeight(menuPtr->tkwin))) { - Tk_GeometryRequest(menuPtr->tkwin, menuPtr->totalWidth, - menuPtr->totalHeight); - } - - /* - * Must always force a redisplay here if the window is mapped - * (even if the size didn't change, something else might have - * changed in the menu, such as a label or accelerator). The - * resize will force a redisplay above. - */ - - TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - - menuPtr->menuFlags &= ~RESIZE_PENDING; -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuSelectImageProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents - * of an image displayed in a menu entry when it is selected. - * - * Results: - * None. - * - * Side effects: - * Arranges for the menu to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuSelectImageProc(clientData, x, y, width, height, imgWidth, - imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - register TkMenuEntry *mePtr = (TkMenuEntry *) clientData; - - if ((mePtr->entryFlags & ENTRY_SELECTED) - && !(mePtr->menuPtr->menuFlags & - REDRAW_PENDING)) { - mePtr->menuPtr->menuFlags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayMenu, (ClientData) mePtr->menuPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * DisplayMenu -- - * - * This procedure is invoked to display a menu widget. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -static void -DisplayMenu(clientData) - ClientData clientData; /* Information about widget. */ -{ - register TkMenu *menuPtr = (TkMenu *) clientData; - register TkMenuEntry *mePtr; - register Tk_Window tkwin = menuPtr->tkwin; - int index, strictMotif; - Tk_Font tkfont = menuPtr->tkfont; - Tk_FontMetrics menuMetrics; - int width; - - menuPtr->menuFlags &= ~REDRAW_PENDING; - if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { - return; - } - - if (menuPtr->menuType == MENUBAR) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, - menuPtr->borderWidth, menuPtr->borderWidth, - Tk_Width(tkwin) - 2 * menuPtr->borderWidth, - Tk_Height(tkwin) - 2 * menuPtr->borderWidth, 0, - TK_RELIEF_FLAT); - } - - strictMotif = Tk_StrictMotif(menuPtr->tkwin); - - /* - * See note in ComputeMenuGeometry. We don't want to be doing font metrics - * all of the time. - */ - - Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); - - /* - * Loop through all of the entries, drawing them one at a time. - */ - - for (index = 0; index < menuPtr->numEntries; index++) { - mePtr = menuPtr->entries[index]; - if (menuPtr->menuType != MENUBAR) { - if (!(mePtr->entryFlags & ENTRY_NEEDS_REDISPLAY)) { - continue; - } - } - mePtr->entryFlags &= ~ENTRY_NEEDS_REDISPLAY; - - if (menuPtr->menuType == MENUBAR) { - width = mePtr->width; - } else { - if (mePtr->entryFlags & ENTRY_LAST_COLUMN) { - width = Tk_Width(menuPtr->tkwin) - mePtr->x - - menuPtr->activeBorderWidth; - } else { - width = mePtr->width + menuPtr->borderWidth; - } - } - TkpDrawMenuEntry(mePtr, Tk_WindowId(menuPtr->tkwin), tkfont, - &menuMetrics, mePtr->x, mePtr->y, width, - mePtr->height, strictMotif, 1); - if ((index > 0) && (menuPtr->menuType != MENUBAR) - && mePtr->columnBreak) { - mePtr = menuPtr->entries[index - 1]; - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, - mePtr->x, mePtr->y + mePtr->height, - mePtr->width, - Tk_Height(tkwin) - mePtr->y - mePtr->height - - menuPtr->activeBorderWidth, 0, - TK_RELIEF_FLAT); - } - } - - if (menuPtr->menuType != MENUBAR) { - int x, y, height; - - if (menuPtr->numEntries == 0) { - x = y = menuPtr->borderWidth; - width = Tk_Width(tkwin) - 2 * menuPtr->activeBorderWidth; - height = Tk_Height(tkwin) - 2 * menuPtr->activeBorderWidth; - } else { - mePtr = menuPtr->entries[menuPtr->numEntries - 1]; - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), - menuPtr->border, mePtr->x, mePtr->y + mePtr->height, - mePtr->width, Tk_Height(tkwin) - mePtr->y - mePtr->height - - menuPtr->activeBorderWidth, 0, - TK_RELIEF_FLAT); - x = mePtr->x + mePtr->width; - y = mePtr->y + mePtr->height; - width = Tk_Width(tkwin) - x - menuPtr->activeBorderWidth; - height = Tk_Height(tkwin) - y - menuPtr->activeBorderWidth; - } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, x, y, - width, height, 0, TK_RELIEF_FLAT); - } - - Tk_Draw3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin), - menuPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), - menuPtr->borderWidth, menuPtr->relief); -} - -/* - *-------------------------------------------------------------- - * - * TkMenuEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on menus. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -void -TkMenuEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkMenu *menuPtr = (TkMenu *) clientData; - - if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { - TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - } else if (eventPtr->type == ConfigureNotify) { - TkEventuallyRecomputeMenu(menuPtr); - TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - } else if (eventPtr->type == ActivateNotify) { - if (menuPtr->menuType == TEAROFF_MENU) { - TkpSetMainMenubar(menuPtr->interp, menuPtr->tkwin, NULL); - } - } else if (eventPtr->type == DestroyNotify) { - if (menuPtr->tkwin != NULL) { - menuPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(menuPtr->interp, menuPtr->widgetCmd); - } - if (menuPtr->menuFlags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayMenu, (ClientData) menuPtr); - } - if (menuPtr->menuFlags & RESIZE_PENDING) { - Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr); - } - TkDestroyMenu(menuPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMenuImageProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents - * of an image displayed in a menu entry. - * - * Results: - * None. - * - * Side effects: - * Arranges for the menu to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -void -TkMenuImageProc(clientData, x, y, width, height, imgWidth, - imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - register TkMenu *menuPtr = ((TkMenuEntry *)clientData)->menuPtr; - - if ((menuPtr->tkwin != NULL) && !(menuPtr->menuFlags - & RESIZE_PENDING)) { - menuPtr->menuFlags |= RESIZE_PENDING; - Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkPostTearoffMenu -- - * - * Posts a menu on the screen. Used to post tearoff menus. On Unix, - * all menus are posted this way. Adjusts the menu's position - * so that it fits on the screen, and maps and raises the menu. - * - * Results: - * Returns a standard Tcl Error. - * - * Side effects: - * The menu is posted. - * - *---------------------------------------------------------------------- - */ - -int -TkPostTearoffMenu(interp, menuPtr, x, y) - Tcl_Interp *interp; /* The interpreter of the menu */ - TkMenu *menuPtr; /* The menu we are posting */ - int x; /* The root X coordinate where we - * are posting */ - int y; /* The root Y coordinate where we - * are posting */ -{ - int vRootX, vRootY, vRootWidth, vRootHeight; - int tmp, result; - - TkActivateMenuEntry(menuPtr, -1); - TkRecomputeMenu(menuPtr); - result = TkPostCommand(menuPtr); - if (result != TCL_OK) { - return result; - } - - /* - * The post commands could have deleted the menu, which means - * we are dead and should go away. - */ - - if (menuPtr->tkwin == NULL) { - return TCL_OK; - } - - /* - * Adjust the position of the menu if necessary to keep it - * visible on the screen. There are two special tricks to - * make this work right: - * - * 1. If a virtual root window manager is being used then - * the coordinates are in the virtual root window of - * menuPtr's parent; since the menu uses override-redirect - * mode it will be in the *real* root window for the screen, - * so we have to map the coordinates from the virtual root - * (if any) to the real root. Can't get the virtual root - * from the menu itself (it will never be seen by the wm) - * so use its parent instead (it would be better to have an - * an option that names a window to use for this...). - * 2. The menu may not have been mapped yet, so its current size - * might be the default 1x1. To compute how much space it - * needs, use its requested size, not its actual size. - * - * Note that this code assumes square screen regions and all - * positive coordinates. This does not work on a Mac with - * multiple monitors. But then again, Tk has other problems - * with this. - */ - - Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY, - &vRootWidth, &vRootHeight); - x += vRootX; - y += vRootY; - tmp = WidthOfScreen(Tk_Screen(menuPtr->tkwin)) - - Tk_ReqWidth(menuPtr->tkwin); - if (x > tmp) { - x = tmp; - } - if (x < 0) { - x = 0; - } - tmp = HeightOfScreen(Tk_Screen(menuPtr->tkwin)) - - Tk_ReqHeight(menuPtr->tkwin); - if (y > tmp) { - y = tmp; - } - if (y < 0) { - y = 0; - } - Tk_MoveToplevelWindow(menuPtr->tkwin, x, y); - if (!Tk_IsMapped(menuPtr->tkwin)) { - Tk_MapWindow(menuPtr->tkwin); - } - TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkPostSubmenu -- - * - * This procedure arranges for a particular submenu (i.e. the - * menu corresponding to a given cascade entry) to be - * posted. - * - * Results: - * A standard Tcl return result. Errors may occur in the - * Tcl commands generated to post and unpost submenus. - * - * Side effects: - * If there is already a submenu posted, it is unposted. - * The new submenu is then posted. - * - *-------------------------------------------------------------- - */ - -int -TkPostSubmenu(interp, menuPtr, mePtr) - Tcl_Interp *interp; /* Used for invoking sub-commands and - * reporting errors. */ - register TkMenu *menuPtr; /* Information about menu as a whole. */ - register TkMenuEntry *mePtr; /* Info about submenu that is to be - * posted. NULL means make sure that - * no submenu is posted. */ -{ - char string[30]; - int result, x, y; - - if (mePtr == menuPtr->postedCascade) { - return TCL_OK; - } - - if (menuPtr->postedCascade != NULL) { - - /* - * Note: when unposting a submenu, we have to redraw the entire - * parent menu. This is because of a combination of the following - * things: - * (a) the submenu partially overlaps the parent. - * (b) the submenu specifies "save under", which causes the X - * server to make a copy of the information under it when it - * is posted. When the submenu is unposted, the X server - * copies this data back and doesn't generate any Expose - * events for the parent. - * (c) the parent may have redisplayed itself after the submenu - * was posted, in which case the saved information is no - * longer correct. - * The simplest solution is just force a complete redisplay of - * the parent. - */ - - TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - result = Tcl_VarEval(interp, menuPtr->postedCascade->name, - " unpost", (char *) NULL); - menuPtr->postedCascade = NULL; - if (result != TCL_OK) { - return result; - } - } - - if ((mePtr != NULL) && (mePtr->name != NULL) - && Tk_IsMapped(menuPtr->tkwin)) { - - /* - * Position the cascade with its upper left corner slightly - * below and to the left of the upper right corner of the - * menu entry (this is an attempt to match Motif behavior). - * - * The menu has to redrawn so that the entry can change relief. - */ - - Tk_GetRootCoords(menuPtr->tkwin, &x, &y); - AdjustMenuCoords(menuPtr, mePtr, &x, &y, string); - result = Tcl_VarEval(interp, mePtr->name, " post ", string, - (char *) NULL); - if (result != TCL_OK) { - return result; - } - menuPtr->postedCascade = mePtr; - TkEventuallyRedrawMenu(menuPtr, mePtr); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * AdjustMenuCoords -- - * - * Adjusts the given coordinates down and the left to give a Motif - * look. - * - * Results: - * None. - * - * Side effects: - * The menu is eventually redrawn if necessary. - * - *---------------------------------------------------------------------- - */ - -static void -AdjustMenuCoords(menuPtr, mePtr, xPtr, yPtr, string) - TkMenu *menuPtr; - TkMenuEntry *mePtr; - int *xPtr; - int *yPtr; - char *string; -{ - if (menuPtr->menuType == MENUBAR) { - *xPtr += mePtr->x; - *yPtr += mePtr->y + mePtr->height; - } else { - *xPtr += Tk_Width(menuPtr->tkwin) - menuPtr->borderWidth - - menuPtr->activeBorderWidth - 2; - *yPtr += mePtr->y - + menuPtr->activeBorderWidth + 2; - } - sprintf(string, "%d %d", *xPtr, *yPtr); -} diff --git a/generic/tkMenubutton.c b/generic/tkMenubutton.c deleted file mode 100644 index da6d901..0000000 --- a/generic/tkMenubutton.c +++ /dev/null @@ -1,865 +0,0 @@ -/* - * tkMenubutton.c -- - * - * This module implements button-like widgets that are used - * to invoke pull-down menus. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMenubutton.c,v 1.2 1998/09/14 18:23:14 stanton Exp $ - */ - -#include "tkMenubutton.h" -#include "tkPort.h" -#include "default.h" - -/* - * Uids internal to menubuttons. - */ - -static Tk_Uid aboveUid = NULL; -static Tk_Uid belowUid = NULL; -static Tk_Uid leftUid = NULL; -static Tk_Uid rightUid = NULL; -static Tk_Uid flushUid = NULL; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENUBUTTON_ACTIVE_BG_COLOR, Tk_Offset(TkMenuButton, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENUBUTTON_ACTIVE_BG_MONO, Tk_Offset(TkMenuButton, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENUBUTTON_ACTIVE_FG_COLOR, Tk_Offset(TkMenuButton, activeFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENUBUTTON_ACTIVE_FG_MONO, Tk_Offset(TkMenuButton, activeFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", - DEF_MENUBUTTON_ANCHOR, Tk_Offset(TkMenuButton, anchor), 0}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENUBUTTON_BG_COLOR, Tk_Offset(TkMenuButton, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENUBUTTON_BG_MONO, Tk_Offset(TkMenuButton, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", - DEF_MENUBUTTON_BITMAP, Tk_Offset(TkMenuButton, bitmap), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_MENUBUTTON_BORDER_WIDTH, Tk_Offset(TkMenuButton, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_MENUBUTTON_CURSOR, Tk_Offset(TkMenuButton, cursor), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-direction", "direction", "Direction", - DEF_MENUBUTTON_DIRECTION, Tk_Offset(TkMenuButton, direction), - 0}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_COLOR, - Tk_Offset(TkMenuButton, disabledFg), - TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_MONO, - Tk_Offset(TkMenuButton, disabledFg), - TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_MENUBUTTON_FONT, Tk_Offset(TkMenuButton, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_MENUBUTTON_FG, Tk_Offset(TkMenuButton, normalFg), 0}, - {TK_CONFIG_STRING, "-height", "height", "Height", - DEF_MENUBUTTON_HEIGHT, Tk_Offset(TkMenuButton, heightString), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG, - Tk_Offset(TkMenuButton, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_MENUBUTTON_HIGHLIGHT, Tk_Offset(TkMenuButton, highlightColorPtr), - 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH, - Tk_Offset(TkMenuButton, highlightWidth), 0}, - {TK_CONFIG_STRING, "-image", "image", "Image", - DEF_MENUBUTTON_IMAGE, Tk_Offset(TkMenuButton, imageString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", - DEF_MENUBUTTON_INDICATOR, Tk_Offset(TkMenuButton, indicatorOn), 0}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_MENUBUTTON_JUSTIFY, Tk_Offset(TkMenuButton, justify), 0}, - {TK_CONFIG_STRING, "-menu", "menu", "Menu", - DEF_MENUBUTTON_MENU, Tk_Offset(TkMenuButton, menuName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_MENUBUTTON_PADX, Tk_Offset(TkMenuButton, padX), 0}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_MENUBUTTON_PADY, Tk_Offset(TkMenuButton, padY), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_MENUBUTTON_RELIEF, Tk_Offset(TkMenuButton, relief), 0}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_MENUBUTTON_STATE, Tk_Offset(TkMenuButton, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_MENUBUTTON_TAKE_FOCUS, Tk_Offset(TkMenuButton, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-text", "text", "Text", - DEF_MENUBUTTON_TEXT, Tk_Offset(TkMenuButton, text), 0}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_MENUBUTTON_TEXT_VARIABLE, Tk_Offset(TkMenuButton, textVarName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-underline", "underline", "Underline", - DEF_MENUBUTTON_UNDERLINE, Tk_Offset(TkMenuButton, underline), 0}, - {TK_CONFIG_STRING, "-width", "width", "Width", - DEF_MENUBUTTON_WIDTH, Tk_Offset(TkMenuButton, widthString), 0}, - {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", - DEF_MENUBUTTON_WRAP_LENGTH, Tk_Offset(TkMenuButton, wrapLength), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void MenuButtonCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData, - int x, int y, int width, int height, int imgWidth, - int imgHeight)); -static char * MenuButtonTextVarProc _ANSI_ARGS_(( - ClientData clientData, Tcl_Interp *interp, - char *name1, char *name2, int flags)); -static int MenuButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp, - TkMenuButton *mbPtr, int argc, char **argv, - int flags)); -static void DestroyMenuButton _ANSI_ARGS_((char *memPtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_MenubuttonCmd -- - * - * This procedure is invoked to process the "button", "label", - * "radiobutton", and "checkbutton" Tcl commands. See the - * user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_MenubuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkMenuButton *mbPtr; - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Create the new window. - */ - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - Tk_SetClass(new, "Menubutton"); - mbPtr = TkpCreateMenuButton(new); - - TkSetClassProcs(new, &tkpMenubuttonClass, (ClientData) mbPtr); - - /* - * Initialize the data structure for the button. - */ - - mbPtr->tkwin = new; - mbPtr->display = Tk_Display (new); - mbPtr->interp = interp; - mbPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(mbPtr->tkwin), - MenuButtonWidgetCmd, (ClientData) mbPtr, MenuButtonCmdDeletedProc); - mbPtr->menuName = NULL; - mbPtr->text = NULL; - mbPtr->underline = -1; - mbPtr->textVarName = NULL; - mbPtr->bitmap = None; - mbPtr->imageString = NULL; - mbPtr->image = NULL; - mbPtr->state = tkNormalUid; - mbPtr->normalBorder = NULL; - mbPtr->activeBorder = NULL; - mbPtr->borderWidth = 0; - mbPtr->relief = TK_RELIEF_FLAT; - mbPtr->highlightWidth = 0; - mbPtr->highlightBgColorPtr = NULL; - mbPtr->highlightColorPtr = NULL; - mbPtr->inset = 0; - mbPtr->tkfont = NULL; - mbPtr->normalFg = NULL; - mbPtr->activeFg = NULL; - mbPtr->disabledFg = NULL; - mbPtr->normalTextGC = None; - mbPtr->activeTextGC = None; - mbPtr->gray = None; - mbPtr->disabledGC = None; - mbPtr->leftBearing = 0; - mbPtr->rightBearing = 0; - mbPtr->widthString = NULL; - mbPtr->heightString = NULL; - mbPtr->width = 0; - mbPtr->width = 0; - mbPtr->wrapLength = 0; - mbPtr->padX = 0; - mbPtr->padY = 0; - mbPtr->anchor = TK_ANCHOR_CENTER; - mbPtr->justify = TK_JUSTIFY_CENTER; - mbPtr->textLayout = NULL; - mbPtr->indicatorOn = 0; - mbPtr->indicatorWidth = 0; - mbPtr->indicatorHeight = 0; - mbPtr->cursor = None; - mbPtr->takeFocus = NULL; - mbPtr->flags = 0; - if (aboveUid == NULL) { - aboveUid = Tk_GetUid("above"); - belowUid = Tk_GetUid("below"); - leftUid = Tk_GetUid("left"); - rightUid = Tk_GetUid("right"); - flushUid = Tk_GetUid("flush"); - } - mbPtr->direction = flushUid; - - Tk_CreateEventHandler(mbPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - MenuButtonEventProc, (ClientData) mbPtr); - if (ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, 0) != TCL_OK) { - Tk_DestroyWindow(mbPtr->tkwin); - return TCL_ERROR; - } - - interp->result = Tk_PathName(mbPtr->tkwin); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * MenuButtonWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -MenuButtonWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about button widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkMenuButton *mbPtr = (TkMenuButton *) clientData; - int result; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) mbPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - result = TCL_ERROR; - } else { - result = Tk_ConfigureValue(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, argv[2], 0); - } - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, argv[2], 0); - } else { - result = ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", - (char *) NULL); - result = TCL_ERROR; - } - Tcl_Release((ClientData) mbPtr); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyMenuButton -- - * - * This procedure is invoked to recycle all of the resources - * associated with a button widget. It is invoked as a - * when-idle handler in order to make sure that there is no - * other use of the button pending at the time of the deletion. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the widget is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyMenuButton(memPtr) - char *memPtr; /* Info about button widget. */ -{ - register TkMenuButton *mbPtr = (TkMenuButton *) memPtr; - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (mbPtr->textVarName != NULL) { - Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuButtonTextVarProc, (ClientData) mbPtr); - } - if (mbPtr->image != NULL) { - Tk_FreeImage(mbPtr->image); - } - if (mbPtr->normalTextGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); - } - if (mbPtr->activeTextGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); - } - if (mbPtr->gray != None) { - Tk_FreeBitmap(mbPtr->display, mbPtr->gray); - } - if (mbPtr->disabledGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); - } - Tk_FreeTextLayout(mbPtr->textLayout); - Tk_FreeOptions(configSpecs, (char *) mbPtr, mbPtr->display, 0); - ckfree((char *) mbPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureMenuButton -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a menubutton widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for mbPtr; old resources get freed, if there - * were any. The menubutton is redisplayed. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureMenuButton(interp, mbPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkMenuButton *mbPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - int result; - Tk_Image image; - - /* - * Eliminate any existing trace on variables monitored by the menubutton. - */ - - if (mbPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, mbPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuButtonTextVarProc, (ClientData) mbPtr); - } - - result = Tk_ConfigureWidget(interp, mbPtr->tkwin, configSpecs, - argc, argv, (char *) mbPtr, flags); - if (result != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few options need special processing, such as setting the - * background from a 3-D border, or filling in complicated - * defaults that couldn't be specified to Tk_ConfigureWidget. - */ - - if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { - Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); - } else { - Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); - if ((mbPtr->state != tkNormalUid) && (mbPtr->state != tkActiveUid) - && (mbPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", mbPtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - mbPtr->state = tkNormalUid; - return TCL_ERROR; - } - } - - if ((mbPtr->direction != aboveUid) && (mbPtr->direction != belowUid) - && (mbPtr->direction != leftUid) && (mbPtr->direction != rightUid) - && (mbPtr->direction != flushUid)) { - Tcl_AppendResult(interp, "bad direction value \"", mbPtr->direction, - "\": must be above, below, left, right, or flush", - (char *) NULL); - mbPtr->direction = belowUid; - return TCL_ERROR; - } - - if (mbPtr->highlightWidth < 0) { - mbPtr->highlightWidth = 0; - } - - if (mbPtr->padX < 0) { - mbPtr->padX = 0; - } - if (mbPtr->padY < 0) { - mbPtr->padY = 0; - } - - /* - * Get the image for the widget, if there is one. Allocate the - * new image before freeing the old one, so that the reference - * count doesn't go to zero and cause image data to be discarded. - */ - - if (mbPtr->imageString != NULL) { - image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, - mbPtr->imageString, MenuButtonImageProc, (ClientData) mbPtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (mbPtr->image != NULL) { - Tk_FreeImage(mbPtr->image); - } - mbPtr->image = image; - - if ((mbPtr->image == NULL) && (mbPtr->bitmap == None) - && (mbPtr->textVarName != NULL)) { - /* - * The menubutton displays a variable. Set up a trace to watch - * for any changes in it. - */ - - char *value; - - value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, - TCL_GLOBAL_ONLY); - } else { - if (mbPtr->text != NULL) { - ckfree(mbPtr->text); - } - mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(mbPtr->text, value); - } - Tcl_TraceVar(interp, mbPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuButtonTextVarProc, (ClientData) mbPtr); - } - - /* - * Recompute the geometry for the button. - */ - - if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { - if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, - &mbPtr->width) != TCL_OK) { - widthError: - Tcl_AddErrorInfo(interp, "\n (processing -width option)"); - return TCL_ERROR; - } - if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, - &mbPtr->height) != TCL_OK) { - heightError: - Tcl_AddErrorInfo(interp, "\n (processing -height option)"); - return TCL_ERROR; - } - } else { - if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) - != TCL_OK) { - goto widthError; - } - if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) - != TCL_OK) { - goto heightError; - } - } - TkMenuButtonWorldChanged((ClientData) mbPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * TkMenuButtonWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * TkMenuButton will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -void -TkMenuButtonWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC gc; - unsigned long mask; - TkMenuButton *mbPtr; - - mbPtr = (TkMenuButton *) instanceData; - - gcValues.font = Tk_FontId(mbPtr->tkfont); - gcValues.foreground = mbPtr->normalFg->pixel; - gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; - - /* - * Note: GraphicsExpose events are disabled in GC's because they're - * used to copy stuff from an off-screen pixmap onto the screen (we know - * that there's no problem with obscured areas). - */ - - gcValues.graphics_exposures = False; - mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; - gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); - if (mbPtr->normalTextGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); - } - mbPtr->normalTextGC = gc; - - gcValues.font = Tk_FontId(mbPtr->tkfont); - gcValues.foreground = mbPtr->activeFg->pixel; - gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel; - mask = GCForeground | GCBackground | GCFont; - gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); - if (mbPtr->activeTextGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); - } - mbPtr->activeTextGC = gc; - - gcValues.font = Tk_FontId(mbPtr->tkfont); - gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; - if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) { - gcValues.foreground = mbPtr->disabledFg->pixel; - mask = GCForeground | GCBackground | GCFont; - } else { - gcValues.foreground = gcValues.background; - mask = GCForeground; - if (mbPtr->gray == None) { - mbPtr->gray = Tk_GetBitmap(NULL, mbPtr->tkwin, - Tk_GetUid("gray50")); - } - if (mbPtr->gray != None) { - gcValues.fill_style = FillStippled; - gcValues.stipple = mbPtr->gray; - mask |= GCFillStyle | GCStipple; - } - } - gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); - if (mbPtr->disabledGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); - } - mbPtr->disabledGC = gc; - - TkpComputeMenuButtonGeometry(mbPtr); - - /* - * Lastly, arrange for the button to be redisplayed. - */ - - if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); - mbPtr->flags |= REDRAW_PENDING; - } -} - -/* - *-------------------------------------------------------------- - * - * MenuButtonEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on buttons. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -MenuButtonEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkMenuButton *mbPtr = (TkMenuButton *) clientData; - if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { - goto redraw; - } else if (eventPtr->type == ConfigureNotify) { - /* - * Must redraw after size changes, since layout could have changed - * and borders will need to be redrawn. - */ - - goto redraw; - } else if (eventPtr->type == DestroyNotify) { - TkpDestroyMenuButton(mbPtr); - if (mbPtr->tkwin != NULL) { - mbPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd); - } - if (mbPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(TkpDisplayMenuButton, (ClientData) mbPtr); - } - Tcl_EventuallyFree((ClientData) mbPtr, DestroyMenuButton); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - mbPtr->flags |= GOT_FOCUS; - if (mbPtr->highlightWidth > 0) { - goto redraw; - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - mbPtr->flags &= ~GOT_FOCUS; - if (mbPtr->highlightWidth > 0) { - goto redraw; - } - } - } - return; - - redraw: - if ((mbPtr->tkwin != NULL) && !(mbPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); - mbPtr->flags |= REDRAW_PENDING; - } -} - -/* - *---------------------------------------------------------------------- - * - * MenuButtonCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -MenuButtonCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkMenuButton *mbPtr = (TkMenuButton *) clientData; - Tk_Window tkwin = mbPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - mbPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * MenuButtonTextVarProc -- - * - * This procedure is invoked when someone changes the variable - * whose contents are to be displayed in a menu button. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The text displayed in the menu button will change to match the - * variable. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -MenuButtonTextVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about button. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -{ - register TkMenuButton *mbPtr = (TkMenuButton *) clientData; - char *value; - - /* - * If the variable is unset, then immediately recreate it unless - * the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, - TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, mbPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuButtonTextVarProc, clientData); - } - return (char *) NULL; - } - - value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (mbPtr->text != NULL) { - ckfree(mbPtr->text); - } - mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(mbPtr->text, value); - TkpComputeMenuButtonGeometry(mbPtr); - - if ((mbPtr->tkwin != NULL) && Tk_IsMapped(mbPtr->tkwin) - && !(mbPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); - mbPtr->flags |= REDRAW_PENDING; - } - return (char *) NULL; -} - -/* - *---------------------------------------------------------------------- - * - * MenuButtonImageProc -- - * - * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents - * of an image displayed in a button. - * - * Results: - * None. - * - * Side effects: - * Arranges for the button to get redisplayed. - * - *---------------------------------------------------------------------- - */ - -static void -MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ -{ - register TkMenuButton *mbPtr = (TkMenuButton *) clientData; - - if (mbPtr->tkwin != NULL) { - TkpComputeMenuButtonGeometry(mbPtr); - if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); - mbPtr->flags |= REDRAW_PENDING; - } - } -} diff --git a/generic/tkMenubutton.h b/generic/tkMenubutton.h deleted file mode 100644 index b032274..0000000 --- a/generic/tkMenubutton.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * tkMenubutton.h -- - * - * Declarations of types and functions used to implement - * the menubutton widget. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMenubutton.h,v 1.4 1998/09/14 18:23:15 stanton Exp $ - */ - -#ifndef _TKMENUBUTTON -#define _TKMENUBUTTON - -#ifndef _TKINT -#include "tkInt.h" -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * A data structure of the following type is kept for each - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the widget. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Needed, among - * other things, so that resources can bee - * freed up even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with menubutton. */ - Tcl_Command widgetCmd; /* Token for menubutton's widget command. */ - char *menuName; /* Name of menu associated with widget. - * Malloc-ed. */ - - /* - * Information about what's displayed in the menu button: - */ - - char *text; /* Text to display in button (malloc'ed) - * or NULL. */ - int underline; /* Index of character to underline. */ - char *textVarName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, button displays the contents - * of this variable. */ - Pixmap bitmap; /* Bitmap to display or None. If not None - * then text and textVar and underline - * are ignored. */ - char *imageString; /* Name of image to display (malloc'ed), or - * NULL. If non-NULL, bitmap, text, and - * textVarName are ignored. */ - Tk_Image image; /* Image to display in window, or NULL if - * none. */ - - /* - * Information used when displaying widget: - */ - - Tk_Uid state; /* State of button for display purposes: - * normal, active, or disabled. */ - Tk_3DBorder normalBorder; /* Structure used to draw 3-D - * border and background when window - * isn't active. NULL means no such - * border exists. */ - Tk_3DBorder activeBorder; /* Structure used to draw 3-D - * border and background when window - * is active. NULL means no such - * border exists. */ - int borderWidth; /* Width of border. */ - int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *normalFg; /* Foreground color in normal mode. */ - XColor *activeFg; /* Foreground color in active mode. NULL - * means use normalFg instead. */ - XColor *disabledFg; /* Foreground color when disabled. NULL - * means use normalFg with a 50% stipple - * instead. */ - GC normalTextGC; /* GC for drawing text in normal mode. */ - GC activeTextGC; /* GC for drawing text in active mode (NULL - * means use normalTextGC). */ - Pixmap gray; /* Pixmap for displaying disabled text/icon if - * disabledFg is NULL. */ - GC disabledGC; /* Used to produce disabled effect. If - * disabledFg isn't NULL, this GC is used to - * draw button text or icon. Otherwise - * text or icon is drawn with normalGC and - * this GC is used to stipple background - * across it. */ - int leftBearing; /* Distance from text origin to leftmost drawn - * pixel (positive means to right). */ - int rightBearing; /* Amount text sticks right from its origin. */ - char *widthString; /* Value of -width option. Malloc'ed. */ - char *heightString; /* Value of -height option. Malloc'ed. */ - int width, height; /* If > 0, these specify dimensions to request - * for window, in characters for text and in - * pixels for bitmaps. In this case the actual - * size of the text string or bitmap is - * ignored in computing desired window size. */ - int wrapLength; /* Line length (in pixels) at which to wrap - * onto next line. <= 0 means don't wrap - * except at newlines. */ - int padX, padY; /* Extra space around text or bitmap (pixels - * on each side). */ - Tk_Anchor anchor; /* Where text/bitmap should be displayed - * inside window region. */ - Tk_Justify justify; /* Justification to use for multi-line text. */ - int textWidth; /* Width needed to display text as requested, - * in pixels. */ - int textHeight; /* Height needed to display text as requested, - * in pixels. */ - Tk_TextLayout textLayout; /* Saved text layout information. */ - int indicatorOn; /* Non-zero means display indicator; 0 means - * don't display. */ - int indicatorHeight; /* Height of indicator in pixels. This same - * amount of extra space is also left on each - * side of the indicator. 0 if no indicator. */ - int indicatorWidth; /* Width of indicator in pixels, including - * indicatorHeight in padding on each side. - * 0 if no indicator. */ - - /* - * Miscellaneous information: - */ - - Tk_Uid direction; /* Direction for where to pop the menu. - * Valid directions are "above", "below", - * "left", "right", and "flush". "flush" - * means that the upper left corner of the - * menubutton is where the menu pops up. - * "above" and "below" will attempt to pop - * the menu compleletly above or below - * the menu respectively. - * "left" and "right" will pop the menu - * left or right, and the active item - * will be next to the button. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int flags; /* Various flags; see below for - * definitions. */ -} TkMenuButton; - -/* - * Flag bits for buttons: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * POSTED: Non-zero means that the menu associated - * with this button has been posted (typically - * because of an active button press). - * GOT_FOCUS: Non-zero means this button currently - * has the input focus. - */ - -#define REDRAW_PENDING 1 -#define POSTED 2 -#define GOT_FOCUS 4 - -/* - * The following constants define the dimensions of the cascade indicator, - * which is displayed if the "-indicatoron" option is true. The units for - * these options are 1/10 millimeters. - */ - -#define INDICATOR_WIDTH 40 -#define INDICATOR_HEIGHT 17 - -/* - * Declaration of variables shared between the files in the button module. - */ - -extern TkClassProcs tkpMenubuttonClass; - -/* - * Declaration of procedures used in the implementation of the button - * widget. - */ - -EXTERN void TkpComputeMenuButtonGeometry _ANSI_ARGS_(( - TkMenuButton *mbPtr)); -EXTERN TkMenuButton * TkpCreateMenuButton _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkpDisplayMenuButton _ANSI_ARGS_(( - ClientData clientData)); -EXTERN void TkpDestroyMenuButton _ANSI_ARGS_(( - TkMenuButton *mbPtr)); -EXTERN void TkMenuButtonWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKMENUBUTTON */ diff --git a/generic/tkMessage.c b/generic/tkMessage.c deleted file mode 100644 index d12c0a3..0000000 --- a/generic/tkMessage.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * tkMessage.c -- - * - * This module implements a message widgets for the Tk - * toolkit. A message widget displays a multi-line string - * in a window according to a particular aspect ratio. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMessage.c,v 1.2 1998/09/14 18:23:15 stanton Exp $ - */ - -#include "tkPort.h" -#include "default.h" -#include "tkInt.h" - -/* - * A data structure of the following type is kept for each message - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the message. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with message. */ - Tcl_Command widgetCmd; /* Token for message's widget command. */ - - /* - * Information used when displaying widget: - */ - - char *string; /* String displayed in message. */ - int numChars; /* Number of characters in string, not - * including terminating NULL character. */ - char *textVarName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, message displays the contents - * of this variable. */ - Tk_3DBorder border; /* Structure used to draw 3-D border and - * background. NULL means a border hasn't - * been created yet. */ - int borderWidth; /* Width of border. */ - int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *fgColorPtr; /* Foreground color in normal mode. */ - int padX, padY; /* User-requested extra space around text. */ - int width; /* User-requested width, in pixels. 0 means - * compute width using aspect ratio below. */ - int aspect; /* Desired aspect ratio for window - * (100*width/height). */ - int msgWidth; /* Width in pixels needed to display - * message. */ - int msgHeight; /* Height in pixels needed to display - * message. */ - Tk_Anchor anchor; /* Where to position text within window region - * if window is larger or smaller than - * needed. */ - Tk_Justify justify; /* Justification for text. */ - - GC textGC; /* GC for drawing text in normal mode. */ - Tk_TextLayout textLayout; /* Saved layout information. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int flags; /* Various flags; see below for - * definitions. */ -} Message; - -/* - * Flag bits for messages: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * GOT_FOCUS: Non-zero means this button currently - * has the input focus. - */ - -#define REDRAW_PENDING 1 -#define GOT_FOCUS 4 - -/* - * Information used for argv parsing. - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", - DEF_MESSAGE_ANCHOR, Tk_Offset(Message, anchor), 0}, - {TK_CONFIG_INT, "-aspect", "aspect", "Aspect", - DEF_MESSAGE_ASPECT, Tk_Offset(Message, aspect), 0}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MESSAGE_BG_COLOR, Tk_Offset(Message, border), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MESSAGE_BG_MONO, Tk_Offset(Message, border), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_MESSAGE_BORDER_WIDTH, Tk_Offset(Message, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_MESSAGE_CURSOR, Tk_Offset(Message, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_MESSAGE_FONT, Tk_Offset(Message, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_MESSAGE_FG, Tk_Offset(Message, fgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_MESSAGE_HIGHLIGHT_BG, - Tk_Offset(Message, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_MESSAGE_HIGHLIGHT, Tk_Offset(Message, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_MESSAGE_HIGHLIGHT_WIDTH, Tk_Offset(Message, highlightWidth), 0}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_MESSAGE_JUSTIFY, Tk_Offset(Message, justify), 0}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_MESSAGE_PADX, Tk_Offset(Message, padX), 0}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_MESSAGE_PADY, Tk_Offset(Message, padY), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_MESSAGE_RELIEF, Tk_Offset(Message, relief), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_MESSAGE_TAKE_FOCUS, Tk_Offset(Message, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-text", "text", "Text", - DEF_MESSAGE_TEXT, Tk_Offset(Message, string), 0}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_MESSAGE_TEXT_VARIABLE, Tk_Offset(Message, textVarName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_MESSAGE_WIDTH, Tk_Offset(Message, width), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void MessageCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void MessageEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static char * MessageTextVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static int MessageWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void MessageWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static void ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr)); -static int ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp, - Message *msgPtr, int argc, char **argv, - int flags)); -static void DestroyMessage _ANSI_ARGS_((char *memPtr)); -static void DisplayMessage _ANSI_ARGS_((ClientData clientData)); - -/* - * The structure below defines message class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs messageClass = { - NULL, /* createProc. */ - MessageWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_MessageCmd -- - * - * This procedure is invoked to process the "message" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_MessageCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Message *msgPtr; - Tk_Window new; - Tk_Window tkwin = (Tk_Window) clientData; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - msgPtr = (Message *) ckalloc(sizeof(Message)); - msgPtr->tkwin = new; - msgPtr->display = Tk_Display(new); - msgPtr->interp = interp; - msgPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(msgPtr->tkwin), - MessageWidgetCmd, (ClientData) msgPtr, MessageCmdDeletedProc); - msgPtr->textLayout = NULL; - msgPtr->string = NULL; - msgPtr->numChars = 0; - msgPtr->textVarName = NULL; - msgPtr->border = NULL; - msgPtr->borderWidth = 0; - msgPtr->relief = TK_RELIEF_FLAT; - msgPtr->highlightWidth = 0; - msgPtr->highlightBgColorPtr = NULL; - msgPtr->highlightColorPtr = NULL; - msgPtr->tkfont = NULL; - msgPtr->fgColorPtr = NULL; - msgPtr->textGC = None; - msgPtr->padX = 0; - msgPtr->padY = 0; - msgPtr->anchor = TK_ANCHOR_CENTER; - msgPtr->width = 0; - msgPtr->aspect = 150; - msgPtr->msgWidth = 0; - msgPtr->msgHeight = 0; - msgPtr->justify = TK_JUSTIFY_LEFT; - msgPtr->cursor = None; - msgPtr->takeFocus = NULL; - msgPtr->flags = 0; - - Tk_SetClass(msgPtr->tkwin, "Message"); - TkSetClassProcs(msgPtr->tkwin, &messageClass, (ClientData) msgPtr); - Tk_CreateEventHandler(msgPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - MessageEventProc, (ClientData) msgPtr); - if (ConfigureMessage(interp, msgPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - interp->result = Tk_PathName(msgPtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(msgPtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * MessageWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -MessageWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about message widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register Message *msgPtr = (Message *) clientData; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - return TCL_ERROR; - } - return Tk_ConfigureValue(interp, msgPtr->tkwin, configSpecs, - (char *) msgPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs, - (char *) msgPtr, (char *) NULL, 0); - } else if (argc == 3) { - return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs, - (char *) msgPtr, argv[2], 0); - } else { - return ConfigureMessage(interp, msgPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - return TCL_ERROR; - } -} - -/* - *---------------------------------------------------------------------- - * - * DestroyMessage -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a message at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the message is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyMessage(memPtr) - char *memPtr; /* Info about message widget. */ -{ - register Message *msgPtr = (Message *) memPtr; - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - Tk_FreeTextLayout(msgPtr->textLayout); - if (msgPtr->textVarName != NULL) { - Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MessageTextVarProc, (ClientData) msgPtr); - } - if (msgPtr->textGC != None) { - Tk_FreeGC(msgPtr->display, msgPtr->textGC); - } - Tk_FreeOptions(configSpecs, (char *) msgPtr, msgPtr->display, 0); - ckfree((char *) msgPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureMessage -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a message widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for msgPtr; old resources get freed, if there - * were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureMessage(interp, msgPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register Message *msgPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - /* - * Eliminate any existing trace on a variable monitored by the message. - */ - - if (msgPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, msgPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MessageTextVarProc, (ClientData) msgPtr); - } - - if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs, - argc, argv, (char *) msgPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * If the message is to display the value of a variable, then set up - * a trace on the variable's value, create the variable if it doesn't - * exist, and fetch its current value. - */ - - if (msgPtr->textVarName != NULL) { - char *value; - - value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string, - TCL_GLOBAL_ONLY); - } else { - if (msgPtr->string != NULL) { - ckfree(msgPtr->string); - } - msgPtr->string = strcpy(ckalloc(strlen(value) + 1), value); - } - Tcl_TraceVar(interp, msgPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MessageTextVarProc, (ClientData) msgPtr); - } - - /* - * A few other options need special processing, such as setting - * the background from a 3-D border or handling special defaults - * that couldn't be specified to Tk_ConfigureWidget. - */ - - msgPtr->numChars = strlen(msgPtr->string); - - Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border); - - if (msgPtr->highlightWidth < 0) { - msgPtr->highlightWidth = 0; - } - - MessageWorldChanged((ClientData) msgPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * MessageWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Message will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -MessageWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC gc; - Tk_FontMetrics fm; - Message *msgPtr; - - msgPtr = (Message *) instanceData; - - gcValues.font = Tk_FontId(msgPtr->tkfont); - gcValues.foreground = msgPtr->fgColorPtr->pixel; - gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues); - if (msgPtr->textGC != None) { - Tk_FreeGC(msgPtr->display, msgPtr->textGC); - } - msgPtr->textGC = gc; - - Tk_GetFontMetrics(msgPtr->tkfont, &fm); - if (msgPtr->padX < 0) { - msgPtr->padX = fm.ascent / 2; - } - if (msgPtr->padY == -1) { - msgPtr->padY = fm.ascent / 4; - } - - /* - * Recompute the desired geometry for the window, and arrange for - * the window to be redisplayed. - */ - - ComputeMessageGeometry(msgPtr); - if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin) - && !(msgPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr); - msgPtr->flags |= REDRAW_PENDING; - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeMessageGeometry -- - * - * Compute the desired geometry for a message window, - * taking into account the desired aspect ratio for the - * window. - * - * Results: - * None. - * - * Side effects: - * Tk_GeometryRequest is called to inform the geometry - * manager of the desired geometry for this window. - * - *-------------------------------------------------------------- - */ - -static void -ComputeMessageGeometry(msgPtr) - register Message *msgPtr; /* Information about window. */ -{ - int width, inc, height; - int thisWidth, thisHeight, maxWidth; - int aspect, lowerBound, upperBound, inset; - - Tk_FreeTextLayout(msgPtr->textLayout); - - inset = msgPtr->borderWidth + msgPtr->highlightWidth; - - /* - * Compute acceptable bounds for the final aspect ratio. - */ - - aspect = msgPtr->aspect/10; - if (aspect < 5) { - aspect = 5; - } - lowerBound = msgPtr->aspect - aspect; - upperBound = msgPtr->aspect + aspect; - - /* - * Do the computation in multiple passes: start off with - * a very wide window, and compute its height. Then change - * the width and try again. Reduce the size of the change - * and iterate until dimensions are found that approximate - * the desired aspect ratio. Or, if the user gave an explicit - * width then just use that. - */ - - if (msgPtr->width > 0) { - width = msgPtr->width; - inc = 0; - } else { - width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2; - inc = width/2; - } - - for ( ; ; inc /= 2) { - msgPtr->textLayout = Tk_ComputeTextLayout(msgPtr->tkfont, - msgPtr->string, msgPtr->numChars, width, msgPtr->justify, - 0, &thisWidth, &thisHeight); - maxWidth = thisWidth + 2 * (inset + msgPtr->padX); - height = thisHeight + 2 * (inset + msgPtr->padY); - - if (inc <= 2) { - break; - } - aspect = (100 * maxWidth) / height; - - if (aspect < lowerBound) { - width += inc; - } else if (aspect > upperBound) { - width -= inc; - } else { - break; - } - Tk_FreeTextLayout(msgPtr->textLayout); - } - msgPtr->msgWidth = thisWidth; - msgPtr->msgHeight = thisHeight; - Tk_GeometryRequest(msgPtr->tkwin, maxWidth, height); - Tk_SetInternalBorder(msgPtr->tkwin, inset); -} - -/* - *-------------------------------------------------------------- - * - * DisplayMessage -- - * - * This procedure redraws the contents of a message window. - * - * Results: - * None. - * - * Side effects: - * Information appears on the screen. - * - *-------------------------------------------------------------- - */ - -static void -DisplayMessage(clientData) - ClientData clientData; /* Information about window. */ -{ - register Message *msgPtr = (Message *) clientData; - register Tk_Window tkwin = msgPtr->tkwin; - int x, y; - - msgPtr->flags &= ~REDRAW_PENDING; - if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { - return; - } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - - /* - * Compute starting y-location for message based on message size - * and anchor option. - */ - - TkComputeAnchor(msgPtr->anchor, tkwin, msgPtr->padX, msgPtr->padY, - msgPtr->msgWidth, msgPtr->msgHeight, &x, &y); - Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC, - msgPtr->textLayout, x, y, 0, -1); - - if (msgPtr->relief != TK_RELIEF_FLAT) { - Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, - msgPtr->highlightWidth, msgPtr->highlightWidth, - Tk_Width(tkwin) - 2*msgPtr->highlightWidth, - Tk_Height(tkwin) - 2*msgPtr->highlightWidth, - msgPtr->borderWidth, msgPtr->relief); - } - if (msgPtr->highlightWidth != 0) { - GC gc; - - if (msgPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin)); - } else { - gc = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin)); - } - Tk_DrawFocusHighlight(tkwin, gc, msgPtr->highlightWidth, - Tk_WindowId(tkwin)); - } -} - -/* - *-------------------------------------------------------------- - * - * MessageEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on messages. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -MessageEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - Message *msgPtr = (Message *) clientData; - - if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) - || (eventPtr->type == ConfigureNotify)) { - goto redraw; - } else if (eventPtr->type == DestroyNotify) { - if (msgPtr->tkwin != NULL) { - msgPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(msgPtr->interp, msgPtr->widgetCmd); - } - if (msgPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayMessage, (ClientData) msgPtr); - } - Tcl_EventuallyFree((ClientData) msgPtr, DestroyMessage); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - msgPtr->flags |= GOT_FOCUS; - if (msgPtr->highlightWidth > 0) { - goto redraw; - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - msgPtr->flags &= ~GOT_FOCUS; - if (msgPtr->highlightWidth > 0) { - goto redraw; - } - } - } - return; - - redraw: - if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr); - msgPtr->flags |= REDRAW_PENDING; - } -} - -/* - *---------------------------------------------------------------------- - * - * MessageCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -MessageCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - Message *msgPtr = (Message *) clientData; - Tk_Window tkwin = msgPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - msgPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * MessageTextVarProc -- - * - * This procedure is invoked when someone changes the variable - * whose contents are to be displayed in a message. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The text displayed in the message will change to match the - * variable. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -MessageTextVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about message. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -{ - register Message *msgPtr = (Message *) clientData; - char *value; - - /* - * If the variable is unset, then immediately recreate it unless - * the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string, - TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, msgPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MessageTextVarProc, clientData); - } - return (char *) NULL; - } - - value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (msgPtr->string != NULL) { - ckfree(msgPtr->string); - } - msgPtr->numChars = strlen(value); - msgPtr->string = (char *) ckalloc((unsigned) (msgPtr->numChars + 1)); - strcpy(msgPtr->string, value); - ComputeMessageGeometry(msgPtr); - - if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin) - && !(msgPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr); - msgPtr->flags |= REDRAW_PENDING; - } - return (char *) NULL; -} diff --git a/generic/tkOption.c b/generic/tkOption.c deleted file mode 100644 index 9b7e17d..0000000 --- a/generic/tkOption.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * tkOption.c -- - * - * This module contains procedures to manage the option - * database, which allows various strings to be associated - * with windows either by name or by class or both. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkOption.c,v 1.2 1998/09/14 18:23:15 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * The option database is stored as one tree for each main window. - * Each name or class field in an option is associated with a node or - * leaf of the tree. For example, the options "x.y.z" and "x.y*a" - * each correspond to three nodes in the tree; they share the nodes - * "x" and "x.y", but have different leaf nodes. One of the following - * structures exists for each node or leaf in the option tree. It is - * actually stored as part of the parent node, and describes a particular - * child of the parent. - */ - -typedef struct Element { - Tk_Uid nameUid; /* Name or class from one element of - * an option spec. */ - union { - struct ElArray *arrayPtr; /* If this is an intermediate node, - * a pointer to a structure describing - * the remaining elements of all - * options whose prefixes are the - * same up through this element. */ - Tk_Uid valueUid; /* For leaf nodes, this is the string - * value of the option. */ - } child; - int priority; /* Used to select among matching - * options. Includes both the - * priority level and a serial #. - * Greater value means higher - * priority. Irrelevant except in - * leaf nodes. */ - int flags; /* OR-ed combination of bits. See - * below for values. */ -} Element; - -/* - * Flags in Element structures: - * - * CLASS - Non-zero means this element refers to a class, - * Zero means this element refers to a name. - * NODE - Zero means this is a leaf element (the child - * field is a value, not a pointer to another node). - * One means this is a node element. - * WILDCARD - Non-zero means this there was a star in the - * original specification just before this element. - * Zero means there was a dot. - */ - -#define TYPE_MASK 0x7 - -#define CLASS 0x1 -#define NODE 0x2 -#define WILDCARD 0x4 - -#define EXACT_LEAF_NAME 0x0 -#define EXACT_LEAF_CLASS 0x1 -#define EXACT_NODE_NAME 0x2 -#define EXACT_NODE_CLASS 0x3 -#define WILDCARD_LEAF_NAME 0x4 -#define WILDCARD_LEAF_CLASS 0x5 -#define WILDCARD_NODE_NAME 0x6 -#define WILDCARD_NODE_CLASS 0x7 - -/* - * The following structure is used to manage a dynamic array of - * Elements. These structures are used for two purposes: to store - * the contents of a node in the option tree, and for the option - * stacks described below. - */ - -typedef struct ElArray { - int arraySize; /* Number of elements actually - * allocated in the "els" array. */ - int numUsed; /* Number of elements currently in - * use out of els. */ - Element *nextToUse; /* Pointer to &els[numUsed]. */ - Element els[1]; /* Array of structures describing - * children of this node. The - * array will actually contain enough - * elements for all of the children - * (and even a few extras, perhaps). - * This must be the last field in - * the structure. */ -} ElArray; - -#define EL_ARRAY_SIZE(numEls) ((unsigned) (sizeof(ElArray) \ - + ((numEls)-1)*sizeof(Element))) -#define INITIAL_SIZE 5 - -/* - * In addition to the option tree, which is a relatively static structure, - * there are eight additional structures called "stacks", which are used - * to speed up queries into the option database. The stack structures - * are designed for the situation where an individual widget makes repeated - * requests for its particular options. The requests differ only in - * their last name/class, so during the first request we extract all - * the options pertaining to the particular widget and save them in a - * stack-like cache; subsequent requests for the same widget can search - * the cache relatively quickly. In fact, the cache is a hierarchical - * one, storing a list of relevant options for this widget and all of - * its ancestors up to the application root; hence the name "stack". - * - * Each of the eight stacks consists of an array of Elements, ordered in - * terms of levels in the window hierarchy. All the elements relevant - * for the top-level widget appear first in the array, followed by all - * those from the next-level widget on the path to the current widget, - * etc. down to those for the current widget. - * - * Cached information is divided into eight stacks according to the - * CLASS, NODE, and WILDCARD flags. Leaf and non-leaf information is - * kept separate to speed up individual probes (non-leaf information is - * only relevant when building the stacks, but isn't relevant when - * making probes; similarly, only non-leaf information is relevant - * when the stacks are being extended to the next widget down in the - * widget hierarchy). Wildcard elements are handled separately from - * "exact" elements because once they appear at a particular level in - * the stack they remain active for all deeper levels; exact elements - * are only relevant at a particular level. For example, when searching - * for options relevant in a particular window, the entire wildcard - * stacks get checked, but only the portions of the exact stacks that - * pertain to the window's parent. Lastly, name and class stacks are - * kept separate because different search keys are used when searching - * them; keeping them separate speeds up the searches. - */ - -#define NUM_STACKS 8 -static ElArray *stacks[NUM_STACKS]; -static TkWindow *cachedWindow = NULL; /* Lowest-level window currently - * loaded in stacks at present. - * NULL means stacks have never - * been used, or have been - * invalidated because of a change - * to the database. */ - -/* - * One of the following structures is used to keep track of each - * level in the stacks. - */ - -typedef struct StackLevel { - TkWindow *winPtr; /* Window corresponding to this stack - * level. */ - int bases[NUM_STACKS]; /* For each stack, index of first - * element on stack corresponding to - * this level (used to restore "numUsed" - * fields when popping out of a level. */ -} StackLevel; - -/* - * Information about all of the stack levels that are currently - * active. This array grows dynamically to become as large as needed. - */ - -static StackLevel *levels = NULL; - /* Array describing current stack. */ -static int numLevels = 0; /* Total space allocated. */ -static int curLevel = -1; /* Highest level currently in use. Note: - * curLevel is never 0! (I don't remember - * why anymore...) */ - -/* - * The variable below is a serial number for all options entered into - * the database so far. It increments on each addition to the option - * database. It is used in computing option priorities, so that the - * most recent entry wins when choosing between options at the same - * priority level. - */ - -static int serial = 0; - -/* - * Special "no match" Element to use as default for searches. - */ - -static Element defaultMatch; - -/* - * Forward declarations for procedures defined in this file: - */ - -static int AddFromString _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, int priority)); -static void ClearOptionTree _ANSI_ARGS_((ElArray *arrayPtr)); -static ElArray * ExtendArray _ANSI_ARGS_((ElArray *arrayPtr, - Element *elPtr)); -static void ExtendStacks _ANSI_ARGS_((ElArray *arrayPtr, - int leaf)); -static int GetDefaultOptions _ANSI_ARGS_((Tcl_Interp *interp, - TkWindow *winPtr)); -static ElArray * NewArray _ANSI_ARGS_((int numEls)); -static void OptionInit _ANSI_ARGS_((TkMainInfo *mainPtr)); -static int ParsePriority _ANSI_ARGS_((Tcl_Interp *interp, - char *string)); -static int ReadOptionFile _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *fileName, int priority)); -static void SetupStacks _ANSI_ARGS_((TkWindow *winPtr, int leaf)); - -/* - *-------------------------------------------------------------- - * - * Tk_AddOption -- - * - * Add a new option to the option database. - * - * Results: - * None. - * - * Side effects: - * Information is added to the option database. - * - *-------------------------------------------------------------- - */ - -void -Tk_AddOption(tkwin, name, value, priority) - Tk_Window tkwin; /* Window token; option will be associated - * with main window for this window. */ - char *name; /* Multi-element name of option. */ - char *value; /* String value for option. */ - int priority; /* Overall priority level to use for - * this option, such as TK_USER_DEFAULT_PRIO - * or TK_INTERACTIVE_PRIO. Must be between - * 0 and TK_MAX_PRIO. */ -{ - TkWindow *winPtr = ((TkWindow *) tkwin)->mainPtr->winPtr; - register ElArray **arrayPtrPtr; - register Element *elPtr; - Element newEl; - register char *p; - char *field; - int count, firstField, length; -#define TMP_SIZE 100 - char tmp[TMP_SIZE+1]; - - if (winPtr->mainPtr->optionRootPtr == NULL) { - OptionInit(winPtr->mainPtr); - } - cachedWindow = NULL; /* Invalidate the cache. */ - - /* - * Compute the priority for the new element, including both the - * overall level and the serial number (to disambiguate with the - * level). - */ - - if (priority < 0) { - priority = 0; - } else if (priority > TK_MAX_PRIO) { - priority = TK_MAX_PRIO; - } - newEl.priority = (priority << 24) + serial; - serial++; - - /* - * Parse the option one field at a time. - */ - - arrayPtrPtr = &(((TkWindow *) tkwin)->mainPtr->optionRootPtr); - p = name; - for (firstField = 1; ; firstField = 0) { - - /* - * Scan the next field from the name and convert it to a Tk_Uid. - * Must copy the field before calling Tk_Uid, so that a terminating - * NULL may be added without modifying the source string. - */ - - if (*p == '*') { - newEl.flags = WILDCARD; - p++; - } else { - newEl.flags = 0; - } - field = p; - while ((*p != 0) && (*p != '.') && (*p != '*')) { - p++; - } - length = p - field; - if (length > TMP_SIZE) { - length = TMP_SIZE; - } - strncpy(tmp, field, (size_t) length); - tmp[length] = 0; - newEl.nameUid = Tk_GetUid(tmp); - if (isupper(UCHAR(*field))) { - newEl.flags |= CLASS; - } - - if (*p != 0) { - - /* - * New element will be a node. If this option can't possibly - * apply to this main window, then just skip it. Otherwise, - * add it to the parent, if it isn't already there, and descend - * into it. - */ - - newEl.flags |= NODE; - if (firstField && !(newEl.flags & WILDCARD) - && (newEl.nameUid != winPtr->nameUid) - && (newEl.nameUid != winPtr->classUid)) { - return; - } - for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; - ; elPtr++, count--) { - if (count == 0) { - newEl.child.arrayPtr = NewArray(5); - *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); - arrayPtrPtr = &((*arrayPtrPtr)->nextToUse[-1].child.arrayPtr); - break; - } - if ((elPtr->nameUid == newEl.nameUid) - && (elPtr->flags == newEl.flags)) { - arrayPtrPtr = &(elPtr->child.arrayPtr); - break; - } - } - if (*p == '.') { - p++; - } - } else { - - /* - * New element is a leaf. Add it to the parent, if it isn't - * already there. If it exists already, keep whichever value - * has highest priority. - */ - - newEl.child.valueUid = Tk_GetUid(value); - for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; - ; elPtr++, count--) { - if (count == 0) { - *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); - return; - } - if ((elPtr->nameUid == newEl.nameUid) - && (elPtr->flags == newEl.flags)) { - if (elPtr->priority < newEl.priority) { - elPtr->priority = newEl.priority; - elPtr->child.valueUid = newEl.child.valueUid; - } - return; - } - } - } - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetOption -- - * - * Retrieve an option from the option database. - * - * Results: - * The return value is the value specified in the option - * database for the given name and class on the given - * window. If there is nothing specified in the database - * for that option, then NULL is returned. - * - * Side effects: - * The internal caches used to speed up option mapping - * may be modified, if this tkwin is different from the - * last tkwin used for option retrieval. - * - *-------------------------------------------------------------- - */ - -Tk_Uid -Tk_GetOption(tkwin, name, className) - Tk_Window tkwin; /* Token for window that option is - * associated with. */ - char *name; /* Name of option. */ - char *className; /* Class of option. NULL means there - * is no class for this option: just - * check for name. */ -{ - Tk_Uid nameId, classId; - register Element *elPtr, *bestPtr; - register int count; - - /* - * Note: no need to call OptionInit here: it will be done by - * the SetupStacks call below (squeeze out those nanoseconds). - */ - - if (tkwin != (Tk_Window) cachedWindow) { - SetupStacks((TkWindow *) tkwin, 1); - } - - nameId = Tk_GetUid(name); - bestPtr = &defaultMatch; - for (elPtr = stacks[EXACT_LEAF_NAME]->els, - count = stacks[EXACT_LEAF_NAME]->numUsed; count > 0; - elPtr++, count--) { - if ((elPtr->nameUid == nameId) - && (elPtr->priority > bestPtr->priority)) { - bestPtr = elPtr; - } - } - for (elPtr = stacks[WILDCARD_LEAF_NAME]->els, - count = stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0; - elPtr++, count--) { - if ((elPtr->nameUid == nameId) - && (elPtr->priority > bestPtr->priority)) { - bestPtr = elPtr; - } - } - if (className != NULL) { - classId = Tk_GetUid(className); - for (elPtr = stacks[EXACT_LEAF_CLASS]->els, - count = stacks[EXACT_LEAF_CLASS]->numUsed; count > 0; - elPtr++, count--) { - if ((elPtr->nameUid == classId) - && (elPtr->priority > bestPtr->priority)) { - bestPtr = elPtr; - } - } - for (elPtr = stacks[WILDCARD_LEAF_CLASS]->els, - count = stacks[WILDCARD_LEAF_CLASS]->numUsed; count > 0; - elPtr++, count--) { - if ((elPtr->nameUid == classId) - && (elPtr->priority > bestPtr->priority)) { - bestPtr = elPtr; - } - } - } - return bestPtr->child.valueUid; -} - -/* - *-------------------------------------------------------------- - * - * Tk_OptionCmd -- - * - * This procedure is invoked to process the "option" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_OptionCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - size_t length; - char c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " cmd arg ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)) { - int priority; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " add pattern value ?priority?\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 4) { - priority = TK_INTERACTIVE_PRIO; - } else { - priority = ParsePriority(interp, argv[4]); - if (priority < 0) { - return TCL_ERROR; - } - } - Tk_AddOption(tkwin, argv[2], argv[3], priority); - return TCL_OK; - } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) { - TkMainInfo *mainPtr; - - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " clear\"", (char *) NULL); - return TCL_ERROR; - } - mainPtr = ((TkWindow *) tkwin)->mainPtr; - if (mainPtr->optionRootPtr != NULL) { - ClearOptionTree(mainPtr->optionRootPtr); - mainPtr->optionRootPtr = NULL; - } - cachedWindow = NULL; - return TCL_OK; - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - Tk_Window window; - Tk_Uid value; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get window name class\"", (char *) NULL); - return TCL_ERROR; - } - window = Tk_NameToWindow(interp, argv[2], tkwin); - if (window == NULL) { - return TCL_ERROR; - } - value = Tk_GetOption(window, argv[3], argv[4]); - if (value != NULL) { - interp->result = value; - } - return TCL_OK; - } else if ((c == 'r') && (strncmp(argv[1], "readfile", length) == 0)) { - int priority; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " readfile fileName ?priority?\"", - (char *) NULL); - return TCL_ERROR; - } - if (argc == 4) { - priority = ParsePriority(interp, argv[3]); - if (priority < 0) { - return TCL_ERROR; - } - } else { - priority = TK_INTERACTIVE_PRIO; - } - return ReadOptionFile(interp, tkwin, argv[2], priority); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be add, clear, get, or readfile", (char *) NULL); - return TCL_ERROR; - } -} - -/* - *-------------------------------------------------------------- - * - * TkOptionDeadWindow -- - * - * This procedure is called whenever a window is deleted. - * It cleans up any option-related stuff associated with - * the window. - * - * Results: - * None. - * - * Side effects: - * Option-related resources are freed. See code below - * for details. - * - *-------------------------------------------------------------- - */ - -void -TkOptionDeadWindow(winPtr) - register TkWindow *winPtr; /* Window to be cleaned up. */ -{ - /* - * If this window is in the option stacks, then clear the stacks. - */ - - if (winPtr->optionLevel != -1) { - int i; - - for (i = 1; i <= curLevel; i++) { - levels[i].winPtr->optionLevel = -1; - } - curLevel = -1; - cachedWindow = NULL; - } - - /* - * If this window was a main window, then delete its option - * database. - */ - - if ((winPtr->mainPtr->winPtr == winPtr) - && (winPtr->mainPtr->optionRootPtr != NULL)) { - ClearOptionTree(winPtr->mainPtr->optionRootPtr); - winPtr->mainPtr->optionRootPtr = NULL; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkOptionClassChanged -- - * - * This procedure is invoked when a window's class changes. If - * the window is on the option cache, this procedure flushes - * any information for the window, since the new class could change - * what is relevant. - * - * Results: - * None. - * - * Side effects: - * The option cache may be flushed in part or in whole. - * - *---------------------------------------------------------------------- - */ - -void -TkOptionClassChanged(winPtr) - TkWindow *winPtr; /* Window whose class changed. */ -{ - int i, j, *basePtr; - ElArray *arrayPtr; - - if (winPtr->optionLevel == -1) { - return; - } - - /* - * Find the lowest stack level that refers to this window, then - * flush all of the levels above the matching one. - */ - - for (i = 1; i <= curLevel; i++) { - if (levels[i].winPtr == winPtr) { - for (j = i; j <= curLevel; j++) { - levels[j].winPtr->optionLevel = -1; - } - curLevel = i-1; - basePtr = levels[i].bases; - for (j = 0; j < NUM_STACKS; j++) { - arrayPtr = stacks[j]; - arrayPtr->numUsed = basePtr[j]; - arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed]; - } - if (curLevel <= 0) { - cachedWindow = NULL; - } else { - cachedWindow = levels[curLevel].winPtr; - } - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ParsePriority -- - * - * Parse a string priority value. - * - * Results: - * The return value is the integer priority level corresponding - * to string, or -1 if string doesn't point to a valid priority level. - * In this case, an error message is left in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ParsePriority(interp, string) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - char *string; /* Describes a priority level, either - * symbolically or numerically. */ -{ - int priority, c; - size_t length; - - c = string[0]; - length = strlen(string); - if ((c == 'w') - && (strncmp(string, "widgetDefault", length) == 0)) { - return TK_WIDGET_DEFAULT_PRIO; - } else if ((c == 's') - && (strncmp(string, "startupFile", length) == 0)) { - return TK_STARTUP_FILE_PRIO; - } else if ((c == 'u') - && (strncmp(string, "userDefault", length) == 0)) { - return TK_USER_DEFAULT_PRIO; - } else if ((c == 'i') - && (strncmp(string, "interactive", length) == 0)) { - return TK_INTERACTIVE_PRIO; - } else { - char *end; - - priority = strtoul(string, &end, 0); - if ((end == string) || (*end != 0) || (priority < 0) - || (priority > 100)) { - Tcl_AppendResult(interp, "bad priority level \"", string, - "\": must be widgetDefault, startupFile, userDefault, ", - "interactive, or a number between 0 and 100", - (char *) NULL); - return -1; - } - } - return priority; -} - -/* - *---------------------------------------------------------------------- - * - * AddFromString -- - * - * Given a string containing lines in the standard format for - * X resources (see other documentation for details on what this - * is), parse the resource specifications and enter them as options - * for tkwin's main window. - * - * Results: - * The return value is a standard Tcl return code. In the case of - * an error in parsing string, TCL_ERROR will be returned and an - * error message will be left in interp->result. The memory at - * string is totally trashed by this procedure. If you care about - * its contents, make a copy before calling here. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -AddFromString(interp, tkwin, string, priority) - Tcl_Interp *interp; /* Interpreter to use for reporting results. */ - Tk_Window tkwin; /* Token for window: options are entered - * for this window's main window. */ - char *string; /* String containing option specifiers. */ - int priority; /* Priority level to use for options in - * this string, such as TK_USER_DEFAULT_PRIO - * or TK_INTERACTIVE_PRIO. Must be between - * 0 and TK_MAX_PRIO. */ -{ - register char *src, *dst; - char *name, *value; - int lineNum; - - src = string; - lineNum = 1; - while (1) { - - /* - * Skip leading white space and empty lines and comment lines, and - * check for the end of the spec. - */ - - while ((*src == ' ') || (*src == '\t')) { - src++; - } - if ((*src == '#') || (*src == '!')) { - do { - src++; - if ((src[0] == '\\') && (src[1] == '\n')) { - src += 2; - lineNum++; - } - } while ((*src != '\n') && (*src != 0)); - } - if (*src == '\n') { - src++; - lineNum++; - continue; - } - if (*src == '\0') { - break; - } - - /* - * Parse off the option name, collapsing out backslash-newline - * sequences of course. - */ - - dst = name = src; - while (*src != ':') { - if ((*src == '\0') || (*src == '\n')) { - sprintf(interp->result, "missing colon on line %d", - lineNum); - return TCL_ERROR; - } - if ((src[0] == '\\') && (src[1] == '\n')) { - src += 2; - lineNum++; - } else { - *dst = *src; - dst++; - src++; - } - } - - /* - * Eliminate trailing white space on the name, and null-terminate - * it. - */ - - while ((dst != name) && ((dst[-1] == ' ') || (dst[-1] == '\t'))) { - dst--; - } - *dst = '\0'; - - /* - * Skip white space between the name and the value. - */ - - src++; - while ((*src == ' ') || (*src == '\t')) { - src++; - } - if (*src == '\0') { - sprintf(interp->result, "missing value on line %d", lineNum); - return TCL_ERROR; - } - - /* - * Parse off the value, squeezing out backslash-newline sequences - * along the way. - */ - - dst = value = src; - while (*src != '\n') { - if (*src == '\0') { - sprintf(interp->result, "missing newline on line %d", - lineNum); - return TCL_ERROR; - } - if ((src[0] == '\\') && (src[1] == '\n')) { - src += 2; - lineNum++; - } else { - *dst = *src; - dst++; - src++; - } - } - *dst = 0; - - /* - * Enter the option into the database. - */ - - Tk_AddOption(tkwin, name, value, priority); - src++; - lineNum++; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ReadOptionFile -- - * - * Read a file of options ("resources" in the old X terminology) - * and load them into the option database. - * - * Results: - * The return value is a standard Tcl return code. In the case of - * an error in parsing string, TCL_ERROR will be returned and an - * error message will be left in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -ReadOptionFile(interp, tkwin, fileName, priority) - Tcl_Interp *interp; /* Interpreter to use for reporting results. */ - Tk_Window tkwin; /* Token for window: options are entered - * for this window's main window. */ - char *fileName; /* Name of file containing options. */ - int priority; /* Priority level to use for options in - * this file, such as TK_USER_DEFAULT_PRIO - * or TK_INTERACTIVE_PRIO. Must be between - * 0 and TK_MAX_PRIO. */ -{ - char *realName, *buffer; - int result, bufferSize; - Tcl_Channel chan; - Tcl_DString newName; - - /* - * Prevent file system access in a safe interpreter. - */ - - if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "can't read options from a file in a", - " safe interpreter", (char *) NULL); - return TCL_ERROR; - } - - realName = Tcl_TranslateFileName(interp, fileName, &newName); - if (realName == NULL) { - return TCL_ERROR; - } - chan = Tcl_OpenFileChannel(interp, realName, "r", 0); - Tcl_DStringFree(&newName); - if (chan == NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't open \"", fileName, - "\": ", Tcl_PosixError(interp), (char *) NULL); - return TCL_ERROR; - } - - /* - * Compute size of file by seeking to the end of the file. This will - * overallocate if we are performing CRLF translation. - */ - - bufferSize = Tcl_Seek(chan, 0L, SEEK_END); - (void) Tcl_Seek(chan, 0L, SEEK_SET); - - if (bufferSize < 0) { - Tcl_AppendResult(interp, "error seeking to end of file \"", - fileName, "\":", Tcl_PosixError(interp), (char *) NULL); - Tcl_Close(NULL, chan); - return TCL_ERROR; - - } - buffer = (char *) ckalloc((unsigned) bufferSize+1); - bufferSize = Tcl_Read(chan, buffer, bufferSize); - if (bufferSize < 0) { - Tcl_AppendResult(interp, "error reading file \"", fileName, "\":", - Tcl_PosixError(interp), (char *) NULL); - Tcl_Close(NULL, chan); - return TCL_ERROR; - } - Tcl_Close(NULL, chan); - buffer[bufferSize] = 0; - result = AddFromString(interp, tkwin, buffer, priority); - ckfree(buffer); - return result; -} - -/* - *-------------------------------------------------------------- - * - * NewArray -- - * - * Create a new ElArray structure of a given size. - * - * Results: - * The return value is a pointer to a properly initialized - * element array with "numEls" space. The array is marked - * as having no active elements. - * - * Side effects: - * Memory is allocated. - * - *-------------------------------------------------------------- - */ - -static ElArray * -NewArray(numEls) - int numEls; /* How many elements of space to allocate. */ -{ - register ElArray *arrayPtr; - - arrayPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(numEls)); - arrayPtr->arraySize = numEls; - arrayPtr->numUsed = 0; - arrayPtr->nextToUse = arrayPtr->els; - return arrayPtr; -} - -/* - *-------------------------------------------------------------- - * - * ExtendArray -- - * - * Add a new element to an array, extending the array if - * necessary. - * - * Results: - * The return value is a pointer to the new array, which - * will be different from arrayPtr if the array got expanded. - * - * Side effects: - * Memory may be allocated or freed. - * - *-------------------------------------------------------------- - */ - -static ElArray * -ExtendArray(arrayPtr, elPtr) - register ElArray *arrayPtr; /* Array to be extended. */ - register Element *elPtr; /* Element to be copied into array. */ -{ - /* - * If the current array has filled up, make it bigger. - */ - - if (arrayPtr->numUsed >= arrayPtr->arraySize) { - register ElArray *newPtr; - - newPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(2*arrayPtr->arraySize)); - newPtr->arraySize = 2*arrayPtr->arraySize; - newPtr->numUsed = arrayPtr->numUsed; - newPtr->nextToUse = &newPtr->els[newPtr->numUsed]; - memcpy((VOID *) newPtr->els, (VOID *) arrayPtr->els, - (arrayPtr->arraySize*sizeof(Element))); - ckfree((char *) arrayPtr); - arrayPtr = newPtr; - } - - *arrayPtr->nextToUse = *elPtr; - arrayPtr->nextToUse++; - arrayPtr->numUsed++; - return arrayPtr; -} - -/* - *-------------------------------------------------------------- - * - * SetupStacks -- - * - * Arrange the stacks so that they cache all the option - * information for a particular window. - * - * Results: - * None. - * - * Side effects: - * The stacks are modified to hold information for tkwin - * and all its ancestors in the window hierarchy. - * - *-------------------------------------------------------------- - */ - -static void -SetupStacks(winPtr, leaf) - TkWindow *winPtr; /* Window for which information is to - * be cached. */ - int leaf; /* Non-zero means this is the leaf - * window being probed. Zero means this - * is an ancestor of the desired leaf. */ -{ - int level, i, *iPtr; - register StackLevel *levelPtr; - register ElArray *arrayPtr; - - /* - * The following array defines the order in which the current - * stacks are searched to find matching entries to add to the - * stacks. Given the current priority-based scheme, the order - * below is no longer relevant; all that matters is that an - * element is on the list *somewhere*. The ordering is a relic - * of the old days when priorities were determined differently. - */ - - static int searchOrder[] = {WILDCARD_NODE_CLASS, WILDCARD_NODE_NAME, - EXACT_NODE_CLASS, EXACT_NODE_NAME, -1}; - - if (winPtr->mainPtr->optionRootPtr == NULL) { - OptionInit(winPtr->mainPtr); - } - - /* - * Step 1: make sure that options are cached for this window's - * parent. - */ - - if (winPtr->parentPtr != NULL) { - level = winPtr->parentPtr->optionLevel; - if ((level == -1) || (cachedWindow == NULL)) { - SetupStacks(winPtr->parentPtr, 0); - level = winPtr->parentPtr->optionLevel; - } - level++; - } else { - level = 1; - } - - /* - * Step 2: pop extra unneeded information off the stacks and - * mark those windows as no longer having cached information. - */ - - if (curLevel >= level) { - while (curLevel >= level) { - levels[curLevel].winPtr->optionLevel = -1; - curLevel--; - } - levelPtr = &levels[level]; - for (i = 0; i < NUM_STACKS; i++) { - arrayPtr = stacks[i]; - arrayPtr->numUsed = levelPtr->bases[i]; - arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed]; - } - } - curLevel = winPtr->optionLevel = level; - - /* - * Step 3: if the root database information isn't loaded or - * isn't valid, initialize level 0 of the stack from the - * database root (this only happens if winPtr is a main window). - */ - - if ((curLevel == 1) - && ((cachedWindow == NULL) - || (cachedWindow->mainPtr != winPtr->mainPtr))) { - for (i = 0; i < NUM_STACKS; i++) { - arrayPtr = stacks[i]; - arrayPtr->numUsed = 0; - arrayPtr->nextToUse = arrayPtr->els; - } - ExtendStacks(winPtr->mainPtr->optionRootPtr, 0); - } - - /* - * Step 4: create a new stack level; grow the level array if - * we've run out of levels. Clear the stacks for EXACT_LEAF_NAME - * and EXACT_LEAF_CLASS (anything that was there is of no use - * any more). - */ - - if (curLevel >= numLevels) { - StackLevel *newLevels; - - newLevels = (StackLevel *) ckalloc((unsigned) - (numLevels*2*sizeof(StackLevel))); - memcpy((VOID *) newLevels, (VOID *) levels, - (numLevels*sizeof(StackLevel))); - ckfree((char *) levels); - numLevels *= 2; - levels = newLevels; - } - levelPtr = &levels[curLevel]; - levelPtr->winPtr = winPtr; - arrayPtr = stacks[EXACT_LEAF_NAME]; - arrayPtr->numUsed = 0; - arrayPtr->nextToUse = arrayPtr->els; - arrayPtr = stacks[EXACT_LEAF_CLASS]; - arrayPtr->numUsed = 0; - arrayPtr->nextToUse = arrayPtr->els; - levelPtr->bases[EXACT_LEAF_NAME] = stacks[EXACT_LEAF_NAME]->numUsed; - levelPtr->bases[EXACT_LEAF_CLASS] = stacks[EXACT_LEAF_CLASS]->numUsed; - levelPtr->bases[EXACT_NODE_NAME] = stacks[EXACT_NODE_NAME]->numUsed; - levelPtr->bases[EXACT_NODE_CLASS] = stacks[EXACT_NODE_CLASS]->numUsed; - levelPtr->bases[WILDCARD_LEAF_NAME] = stacks[WILDCARD_LEAF_NAME]->numUsed; - levelPtr->bases[WILDCARD_LEAF_CLASS] = stacks[WILDCARD_LEAF_CLASS]->numUsed; - levelPtr->bases[WILDCARD_NODE_NAME] = stacks[WILDCARD_NODE_NAME]->numUsed; - levelPtr->bases[WILDCARD_NODE_CLASS] = stacks[WILDCARD_NODE_CLASS]->numUsed; - - - /* - * Step 5: scan the current stack level looking for matches to this - * window's name or class; where found, add new information to the - * stacks. - */ - - for (iPtr = searchOrder; *iPtr != -1; iPtr++) { - register Element *elPtr; - int count; - Tk_Uid id; - - i = *iPtr; - if (i & CLASS) { - id = winPtr->classUid; - } else { - id = winPtr->nameUid; - } - elPtr = stacks[i]->els; - count = levelPtr->bases[i]; - - /* - * For wildcard stacks, check all entries; for non-wildcard - * stacks, only check things that matched in the parent. - */ - - if (!(i & WILDCARD)) { - elPtr += levelPtr[-1].bases[i]; - count -= levelPtr[-1].bases[i]; - } - for ( ; count > 0; elPtr++, count--) { - if (elPtr->nameUid != id) { - continue; - } - ExtendStacks(elPtr->child.arrayPtr, leaf); - } - } - cachedWindow = winPtr; -} - -/* - *-------------------------------------------------------------- - * - * ExtendStacks -- - * - * Given an element array, copy all the elements from the - * array onto the system stacks (except for irrelevant leaf - * elements). - * - * Results: - * None. - * - * Side effects: - * The option stacks are extended. - * - *-------------------------------------------------------------- - */ - -static void -ExtendStacks(arrayPtr, leaf) - ElArray *arrayPtr; /* Array of elements to copy onto stacks. */ - int leaf; /* If zero, then don't copy exact leaf - * elements. */ -{ - register int count; - register Element *elPtr; - - for (elPtr = arrayPtr->els, count = arrayPtr->numUsed; - count > 0; elPtr++, count--) { - if (!(elPtr->flags & (NODE|WILDCARD)) && !leaf) { - continue; - } - stacks[elPtr->flags] = ExtendArray(stacks[elPtr->flags], elPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * OptionInit -- - * - * Initialize data structures for option handling. - * - * Results: - * None. - * - * Side effects: - * Option-related data structures get initialized. - * - *-------------------------------------------------------------- - */ - -static void -OptionInit(mainPtr) - register TkMainInfo *mainPtr; /* Top-level information about - * window that isn't initialized - * yet. */ -{ - int i; - Tcl_Interp *interp; - - /* - * First, once-only initialization. - */ - - if (numLevels == 0) { - - numLevels = 5; - levels = (StackLevel *) ckalloc((unsigned) (5*sizeof(StackLevel))); - for (i = 0; i < NUM_STACKS; i++) { - stacks[i] = NewArray(10); - levels[0].bases[i] = 0; - } - - defaultMatch.nameUid = NULL; - defaultMatch.child.valueUid = NULL; - defaultMatch.priority = -1; - defaultMatch.flags = 0; - } - - /* - * Then, per-main-window initialization. Create and delete dummy - * interpreter for message logging. - */ - - mainPtr->optionRootPtr = NewArray(20); - interp = Tcl_CreateInterp(); - (void) GetDefaultOptions(interp, mainPtr->winPtr); - Tcl_DeleteInterp(interp); -} - -/* - *-------------------------------------------------------------- - * - * ClearOptionTree -- - * - * This procedure is called to erase everything in a - * hierarchical option database. - * - * Results: - * None. - * - * Side effects: - * All the options associated with arrayPtr are deleted, - * along with all option subtrees. The space pointed to - * by arrayPtr is freed. - * - *-------------------------------------------------------------- - */ - -static void -ClearOptionTree(arrayPtr) - ElArray *arrayPtr; /* Array of options; delete everything - * referred to recursively by this. */ -{ - register Element *elPtr; - int count; - - for (count = arrayPtr->numUsed, elPtr = arrayPtr->els; count > 0; - count--, elPtr++) { - if (elPtr->flags & NODE) { - ClearOptionTree(elPtr->child.arrayPtr); - } - } - ckfree((char *) arrayPtr); -} - -/* - *-------------------------------------------------------------- - * - * GetDefaultOptions -- - * - * This procedure is invoked to load the default set of options - * for a window. - * - * Results: - * None. - * - * Side effects: - * Options are added to those for winPtr's main window. If - * there exists a RESOURCE_MANAGER proprety for winPtr's - * display, that is used. Otherwise, the .Xdefaults file in - * the user's home directory is used. - * - *-------------------------------------------------------------- - */ - -static int -GetDefaultOptions(interp, winPtr) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - TkWindow *winPtr; /* Fetch option defaults for main window - * associated with this. */ -{ - char *regProp; - int result, actualFormat; - unsigned long numItems, bytesAfter; - Atom actualType; - - /* - * Try the RESOURCE_MANAGER property on the root window first. - */ - - regProp = NULL; - result = XGetWindowProperty(winPtr->display, - RootWindow(winPtr->display, 0), - XA_RESOURCE_MANAGER, 0, 100000, - False, XA_STRING, &actualType, &actualFormat, - &numItems, &bytesAfter, (unsigned char **) ®Prop); - - if ((result == Success) && (actualType == XA_STRING) - && (actualFormat == 8)) { - result = AddFromString(interp, (Tk_Window) winPtr, regProp, - TK_USER_DEFAULT_PRIO); - XFree(regProp); - return result; - } - - /* - * No luck there. Try a .Xdefaults file in the user's home - * directory. - */ - - if (regProp != NULL) { - XFree(regProp); - } - result = ReadOptionFile(interp, (Tk_Window) winPtr, "~/.Xdefaults", - TK_USER_DEFAULT_PRIO); - return result; -} diff --git a/generic/tkPack.c b/generic/tkPack.c deleted file mode 100644 index 380315a..0000000 --- a/generic/tkPack.c +++ /dev/null @@ -1,1727 +0,0 @@ -/* - * tkPack.c -- - * - * This file contains code to implement the "packer" - * geometry manager for Tk. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkPack.c,v 1.2 1998/09/14 18:23:15 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side; - -/* For each window that the packer cares about (either because - * the window is managed by the packer or because the window - * has slaves that are managed by the packer), there is a - * structure of the following type: - */ - -typedef struct Packer { - Tk_Window tkwin; /* Tk token for window. NULL means that - * the window has been deleted, but the - * packet hasn't had a chance to clean up - * yet because the structure is still in - * use. */ - struct Packer *masterPtr; /* Master window within which this window - * is packed (NULL means this window - * isn't managed by the packer). */ - struct Packer *nextPtr; /* Next window packed within same - * parent. List is priority-ordered: - * first on list gets packed first. */ - struct Packer *slavePtr; /* First in list of slaves packed - * inside this window (NULL means - * no packed slaves). */ - Side side; /* Side of parent against which - * this window is packed. */ - Tk_Anchor anchor; /* If frame allocated for window is larger - * than window needs, this indicates how - * where to position window in frame. */ - int padX, padY; /* Total additional pixels to leave around the - * window (half of this space is left on each - * side). This is space *outside* the window: - * we'll allocate extra space in frame but - * won't enlarge window). */ - int iPadX, iPadY; /* Total extra pixels to allocate inside the - * window (half this amount will appear on - * each side). */ - int doubleBw; /* Twice the window's last known border - * width. If this changes, the window - * must be repacked within its parent. */ - int *abortPtr; /* If non-NULL, it means that there is a nested - * call to ArrangePacking already working on - * this window. *abortPtr may be set to 1 to - * abort that nested call. This happens, for - * example, if tkwin or any of its slaves - * is deleted. */ - int flags; /* Miscellaneous flags; see below - * for definitions. */ -} Packer; - -/* - * Flag values for Packer structures: - * - * REQUESTED_REPACK: 1 means a Tcl_DoWhenIdle request - * has already been made to repack - * all the slaves of this window. - * FILLX: 1 means if frame allocated for window - * is wider than window needs, expand window - * to fill frame. 0 means don't make window - * any larger than needed. - * FILLY: Same as FILLX, except for height. - * EXPAND: 1 means this window's frame will absorb any - * extra space in the parent window. - * OLD_STYLE: 1 means this window is being managed with - * the old-style packer algorithms (before - * Tk version 3.3). The main difference is - * that padding and filling are done differently. - * DONT_PROPAGATE: 1 means don't set this window's requested - * size. 0 means if this window is a master - * then Tk will set its requested size to fit - * the needs of its slaves. - */ - -#define REQUESTED_REPACK 1 -#define FILLX 2 -#define FILLY 4 -#define EXPAND 8 -#define OLD_STYLE 16 -#define DONT_PROPAGATE 32 - -/* - * Hash table used to map from Tk_Window tokens to corresponding - * Packer structures: - */ - -static Tcl_HashTable packerHashTable; - -/* - * Have statics in this module been initialized? - */ - -static int initialized = 0; - -/* - * The following structure is the official type record for the - * packer: - */ - -static void PackReqProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void PackLostSlaveProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); - -static Tk_GeomMgr packerType = { - "pack", /* name */ - PackReqProc, /* requestProc */ - PackLostSlaveProc, /* lostSlaveProc */ -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void ArrangePacking _ANSI_ARGS_((ClientData clientData)); -static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int argc, char *argv[])); -static void DestroyPacker _ANSI_ARGS_((char *memPtr)); -static Packer * GetPacker _ANSI_ARGS_((Tk_Window tkwin)); -static int PackAfter _ANSI_ARGS_((Tcl_Interp *interp, - Packer *prevPtr, Packer *masterPtr, int argc, - char **argv)); -static void PackReqProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void PackStructureProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void Unlink _ANSI_ARGS_((Packer *packPtr)); -static int XExpansion _ANSI_ARGS_((Packer *slavePtr, - int cavityWidth)); -static int YExpansion _ANSI_ARGS_((Packer *slavePtr, - int cavityHeight)); - -/* - *-------------------------------------------------------------- - * - * Tk_PackCmd -- - * - * This procedure is invoked to process the "pack" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_PackCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - size_t length; - int c; - - if ((argc >= 2) && (argv[1][0] == '.')) { - return ConfigureSlaves(interp, tkwin, argc-1, argv+1); - } - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option arg ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (length >= 2) - && (strncmp(argv[1], "after", length) == 0)) { - Packer *prevPtr; - Tk_Window tkwin2; - - tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - prevPtr = GetPacker(tkwin2); - if (prevPtr->masterPtr == NULL) { - Tcl_AppendResult(interp, "window \"", argv[2], - "\" isn't packed", (char *) NULL); - return TCL_ERROR; - } - return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3); - } else if ((c == 'a') && (length >= 2) - && (strncmp(argv[1], "append", length) == 0)) { - Packer *masterPtr; - register Packer *prevPtr; - Tk_Window tkwin2; - - tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - masterPtr = GetPacker(tkwin2); - prevPtr = masterPtr->slavePtr; - if (prevPtr != NULL) { - while (prevPtr->nextPtr != NULL) { - prevPtr = prevPtr->nextPtr; - } - } - return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3); - } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) { - Packer *packPtr, *masterPtr; - register Packer *prevPtr; - Tk_Window tkwin2; - - tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - packPtr = GetPacker(tkwin2); - if (packPtr->masterPtr == NULL) { - Tcl_AppendResult(interp, "window \"", argv[2], - "\" isn't packed", (char *) NULL); - return TCL_ERROR; - } - masterPtr = packPtr->masterPtr; - prevPtr = masterPtr->slavePtr; - if (prevPtr == packPtr) { - prevPtr = NULL; - } else { - for ( ; ; prevPtr = prevPtr->nextPtr) { - if (prevPtr == NULL) { - panic("\"pack before\" couldn't find predecessor"); - } - if (prevPtr->nextPtr == packPtr) { - break; - } - } - } - return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { - if (argv[2][0] != '.') { - Tcl_AppendResult(interp, "bad argument \"", argv[2], - "\": must be name of window", (char *) NULL); - return TCL_ERROR; - } - return ConfigureSlaves(interp, tkwin, argc-2, argv+2); - } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) { - Tk_Window slave; - Packer *slavePtr; - int i; - - for (i = 2; i < argc; i++) { - slave = Tk_NameToWindow(interp, argv[i], tkwin); - if (slave == NULL) { - continue; - } - slavePtr = GetPacker(slave); - if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) { - Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, - slavePtr->masterPtr->tkwin); - } - Unlink(slavePtr); - Tk_UnmapWindow(slavePtr->tkwin); - } - } - } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { - register Packer *slavePtr; - Tk_Window slave; - char buffer[300]; - static char *sideNames[] = {"top", "bottom", "left", "right"}; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " info window\"", (char *) NULL); - return TCL_ERROR; - } - slave = Tk_NameToWindow(interp, argv[2], tkwin); - if (slave == NULL) { - return TCL_ERROR; - } - slavePtr = GetPacker(slave); - if (slavePtr->masterPtr == NULL) { - Tcl_AppendResult(interp, "window \"", argv[2], - "\" isn't packed", (char *) NULL); - return TCL_ERROR; - } - Tcl_AppendElement(interp, "-in"); - Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin)); - Tcl_AppendElement(interp, "-anchor"); - Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor)); - Tcl_AppendResult(interp, " -expand ", - (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ", - (char *) NULL); - switch (slavePtr->flags & (FILLX|FILLY)) { - case 0: - Tcl_AppendResult(interp, "none", (char *) NULL); - break; - case FILLX: - Tcl_AppendResult(interp, "x", (char *) NULL); - break; - case FILLY: - Tcl_AppendResult(interp, "y", (char *) NULL); - break; - case FILLX|FILLY: - Tcl_AppendResult(interp, "both", (char *) NULL); - break; - } - sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d", - slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2, - slavePtr->padY/2); - Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side], - (char *) NULL); - } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) { - Tk_Window master; - Packer *masterPtr; - int propagate; - - if (argc > 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " propagate window ?boolean?\"", (char *) NULL); - return TCL_ERROR; - } - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetPacker(master); - if (argc == 3) { - if (masterPtr->flags & DONT_PROPAGATE) { - interp->result = "0"; - } else { - interp->result = "1"; - } - return TCL_OK; - } - if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) { - return TCL_ERROR; - } - if (propagate) { - masterPtr->flags &= ~DONT_PROPAGATE; - - /* - * Repack the master to allow new geometry information to - * propagate upwards to the master's master. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_REPACK)) { - masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); - } - } else { - masterPtr->flags |= DONT_PROPAGATE; - } - } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) { - Tk_Window master; - Packer *masterPtr, *slavePtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " slaves window\"", (char *) NULL); - return TCL_ERROR; - } - master = Tk_NameToWindow(interp, argv[2], tkwin); - if (master == NULL) { - return TCL_ERROR; - } - masterPtr = GetPacker(master); - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin)); - } - } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) { - Tk_Window tkwin2; - Packer *packPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " unpack window\"", (char *) NULL); - return TCL_ERROR; - } - tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - packPtr = GetPacker(tkwin2); - if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) { - Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) { - Tk_UnmaintainGeometry(packPtr->tkwin, - packPtr->masterPtr->tkwin); - } - Unlink(packPtr); - Tk_UnmapWindow(packPtr->tkwin); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be configure, forget, info, ", - "propagate, or slaves", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * PackReqProc -- - * - * This procedure is invoked by Tk_GeometryRequest for - * windows managed by the packer. - * - * Results: - * None. - * - * Side effects: - * Arranges for tkwin, and all its managed siblings, to - * be re-packed at the next idle point. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -PackReqProc(clientData, tkwin) - ClientData clientData; /* Packer's information about - * window that got new preferred - * geometry. */ - Tk_Window tkwin; /* Other Tk-related information - * about the window. */ -{ - register Packer *packPtr = (Packer *) clientData; - - packPtr = packPtr->masterPtr; - if (!(packPtr->flags & REQUESTED_REPACK)) { - packPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * PackLostSlaveProc -- - * - * This procedure is invoked by Tk whenever some other geometry - * claims control over a slave that used to be managed by us. - * - * Results: - * None. - * - * Side effects: - * Forgets all packer-related information about the slave. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -PackLostSlaveProc(clientData, tkwin) - ClientData clientData; /* Packer structure for slave window that - * was stolen away. */ - Tk_Window tkwin; /* Tk's handle for the slave window. */ -{ - register Packer *slavePtr = (Packer *) clientData; - - if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); - } - Unlink(slavePtr); - Tk_UnmapWindow(slavePtr->tkwin); -} - -/* - *-------------------------------------------------------------- - * - * ArrangePacking -- - * - * This procedure is invoked (using the Tcl_DoWhenIdle - * mechanism) to re-layout a set of windows managed by - * the packer. It is invoked at idle time so that a - * series of packer requests can be merged into a single - * layout operation. - * - * Results: - * None. - * - * Side effects: - * The packed slaves of masterPtr may get resized or - * moved. - * - *-------------------------------------------------------------- - */ - -static void -ArrangePacking(clientData) - ClientData clientData; /* Structure describing parent whose slaves - * are to be re-layed out. */ -{ - register Packer *masterPtr = (Packer *) clientData; - register Packer *slavePtr; - int cavityX, cavityY, cavityWidth, cavityHeight; - /* These variables keep track of the - * as-yet-unallocated space remaining in - * the middle of the parent window. */ - int frameX, frameY, frameWidth, frameHeight; - /* These variables keep track of the frame - * allocated to the current window. */ - int x, y, width, height; /* These variables are used to hold the - * actual geometry of the current window. */ - int intBWidth; /* Width of internal border in parent window, - * if any. */ - int abort; /* May get set to non-zero to abort this - * repacking operation. */ - int borderX, borderY; - int maxWidth, maxHeight, tmp; - - masterPtr->flags &= ~REQUESTED_REPACK; - - /* - * If the parent has no slaves anymore, then don't do anything - * at all: just leave the parent's size as-is. - */ - - if (masterPtr->slavePtr == NULL) { - return; - } - - /* - * Abort any nested call to ArrangePacking for this window, since - * we'll do everything necessary here, and set up so this call - * can be aborted if necessary. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - masterPtr->abortPtr = &abort; - abort = 0; - Tcl_Preserve((ClientData) masterPtr); - - /* - * Pass #1: scan all the slaves to figure out the total amount - * of space needed. Two separate width and height values are - * computed: - * - * width - Holds the sum of the widths (plus padding) of - * all the slaves seen so far that were packed LEFT - * or RIGHT. - * height - Holds the sum of the heights (plus padding) of - * all the slaves seen so far that were packed TOP - * or BOTTOM. - * - * maxWidth - Gradually builds up the width needed by the master - * to just barely satisfy all the slave's needs. For - * each slave, the code computes the width needed for - * all the slaves so far and updates maxWidth if the - * new value is greater. - * maxHeight - Same as maxWidth, except keeps height info. - */ - - intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin); - width = height = maxWidth = maxHeight = 2*intBWidth; - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { - tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padX + slavePtr->iPadX + width; - if (tmp > maxWidth) { - maxWidth = tmp; - } - height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padY + slavePtr->iPadY; - } else { - tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padY + slavePtr->iPadY + height; - if (tmp > maxHeight) { - maxHeight = tmp; - } - width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padX + slavePtr->iPadX; - } - } - if (width > maxWidth) { - maxWidth = width; - } - if (height > maxHeight) { - maxHeight = height; - } - - /* - * If the total amount of space needed in the parent window has - * changed, and if we're propagating geometry information, then - * notify the next geometry manager up and requeue ourselves to - * start again after the parent has had a chance to - * resize us. - */ - - if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin)) - || (maxHeight != Tk_ReqHeight(masterPtr->tkwin))) - && !(masterPtr->flags & DONT_PROPAGATE)) { - Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight); - masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); - goto done; - } - - /* - * Pass #2: scan the slaves a second time assigning - * new sizes. The "cavity" variables keep track of the - * unclaimed space in the cavity of the window; this - * shrinks inward as we allocate windows around the - * edges. The "frame" variables keep track of the space - * allocated to the current window and its frame. The - * current window is then placed somewhere inside the - * frame, depending on anchor. - */ - - cavityX = cavityY = x = y = intBWidth; - cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth; - cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth; - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { - frameWidth = cavityWidth; - frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padY + slavePtr->iPadY; - if (slavePtr->flags & EXPAND) { - frameHeight += YExpansion(slavePtr, cavityHeight); - } - cavityHeight -= frameHeight; - if (cavityHeight < 0) { - frameHeight += cavityHeight; - cavityHeight = 0; - } - frameX = cavityX; - if (slavePtr->side == TOP) { - frameY = cavityY; - cavityY += frameHeight; - } else { - frameY = cavityY + cavityHeight; - } - } else { - frameHeight = cavityHeight; - frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padX + slavePtr->iPadX; - if (slavePtr->flags & EXPAND) { - frameWidth += XExpansion(slavePtr, cavityWidth); - } - cavityWidth -= frameWidth; - if (cavityWidth < 0) { - frameWidth += cavityWidth; - cavityWidth = 0; - } - frameY = cavityY; - if (slavePtr->side == LEFT) { - frameX = cavityX; - cavityX += frameWidth; - } else { - frameX = cavityX + cavityWidth; - } - } - - /* - * Now that we've got the size of the frame for the window, - * compute the window's actual size and location using the - * fill, padding, and frame factors. The variables "borderX" - * and "borderY" are used to handle the differences between - * old-style packing and the new style (in old-style, iPadX - * and iPadY are always zero and padding is completely ignored - * except when computing frame size). - */ - - if (slavePtr->flags & OLD_STYLE) { - borderX = borderY = 0; - } else { - borderX = slavePtr->padX; - borderY = slavePtr->padY; - } - width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->iPadX; - if ((slavePtr->flags & FILLX) - || (width > (frameWidth - borderX))) { - width = frameWidth - borderX; - } - height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->iPadY; - if ((slavePtr->flags & FILLY) - || (height > (frameHeight - borderY))) { - height = frameHeight - borderY; - } - borderX /= 2; - borderY /= 2; - switch (slavePtr->anchor) { - case TK_ANCHOR_N: - x = frameX + (frameWidth - width)/2; - y = frameY + borderY; - break; - case TK_ANCHOR_NE: - x = frameX + frameWidth - width - borderX; - y = frameY + borderY; - break; - case TK_ANCHOR_E: - x = frameX + frameWidth - width - borderX; - y = frameY + (frameHeight - height)/2; - break; - case TK_ANCHOR_SE: - x = frameX + frameWidth - width - borderX; - y = frameY + frameHeight - height - borderY; - break; - case TK_ANCHOR_S: - x = frameX + (frameWidth - width)/2; - y = frameY + frameHeight - height - borderY; - break; - case TK_ANCHOR_SW: - x = frameX + borderX; - y = frameY + frameHeight - height - borderY; - break; - case TK_ANCHOR_W: - x = frameX + borderX; - y = frameY + (frameHeight - height)/2; - break; - case TK_ANCHOR_NW: - x = frameX + borderX; - y = frameY + borderY; - break; - case TK_ANCHOR_CENTER: - x = frameX + (frameWidth - width)/2; - y = frameY + (frameHeight - height)/2; - break; - default: - panic("bad frame factor in ArrangePacking"); - } - width -= slavePtr->doubleBw; - height -= slavePtr->doubleBw; - - /* - * The final step is to set the position, size, and mapped/unmapped - * state of the slave. If the slave is a child of the master, then - * do this here. Otherwise let Tk_MaintainGeometry do the work. - */ - - if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) { - if ((width <= 0) || (height <= 0)) { - Tk_UnmapWindow(slavePtr->tkwin); - } else { - if ((x != Tk_X(slavePtr->tkwin)) - || (y != Tk_Y(slavePtr->tkwin)) - || (width != Tk_Width(slavePtr->tkwin)) - || (height != Tk_Height(slavePtr->tkwin))) { - Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height); - } - if (abort) { - goto done; - } - - /* - * Don't map the slave if the master isn't mapped: wait - * until the master gets mapped later. - */ - - if (Tk_IsMapped(masterPtr->tkwin)) { - Tk_MapWindow(slavePtr->tkwin); - } - } - } else { - if ((width <= 0) || (height <= 0)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin); - Tk_UnmapWindow(slavePtr->tkwin); - } else { - Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin, - x, y, width, height); - } - } - - /* - * Changes to the window's structure could cause almost anything - * to happen, including deleting the parent or child. If this - * happens, we'll be told to abort. - */ - - if (abort) { - goto done; - } - } - - done: - masterPtr->abortPtr = NULL; - Tcl_Release((ClientData) masterPtr); -} - -/* - *---------------------------------------------------------------------- - * - * XExpansion -- - * - * Given a list of packed slaves, the first of which is packed - * on the left or right and is expandable, compute how much to - * expand the child. - * - * Results: - * The return value is the number of additional pixels to give to - * the child. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -XExpansion(slavePtr, cavityWidth) - register Packer *slavePtr; /* First in list of remaining - * slaves. */ - int cavityWidth; /* Horizontal space left for all - * remaining slaves. */ -{ - int numExpand, minExpand, curExpand; - int childWidth; - - /* - * This procedure is tricky because windows packed top or bottom can - * be interspersed among expandable windows packed left or right. - * Scan through the list, keeping a running sum of the widths of - * all left and right windows (actually, count the cavity space not - * allocated) and a running count of all expandable left and right - * windows. At each top or bottom window, and at the end of the - * list, compute the expansion factor that seems reasonable at that - * point. Return the smallest factor seen at any of these points. - */ - - minExpand = cavityWidth; - numExpand = 0; - for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { - childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padX + slavePtr->iPadX; - if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { - curExpand = (cavityWidth - childWidth)/numExpand; - if (curExpand < minExpand) { - minExpand = curExpand; - } - } else { - cavityWidth -= childWidth; - if (slavePtr->flags & EXPAND) { - numExpand++; - } - } - } - curExpand = cavityWidth/numExpand; - if (curExpand < minExpand) { - minExpand = curExpand; - } - return (minExpand < 0) ? 0 : minExpand; -} - -/* - *---------------------------------------------------------------------- - * - * YExpansion -- - * - * Given a list of packed slaves, the first of which is packed - * on the top or bottom and is expandable, compute how much to - * expand the child. - * - * Results: - * The return value is the number of additional pixels to give to - * the child. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -YExpansion(slavePtr, cavityHeight) - register Packer *slavePtr; /* First in list of remaining - * slaves. */ - int cavityHeight; /* Vertical space left for all - * remaining slaves. */ -{ - int numExpand, minExpand, curExpand; - int childHeight; - - /* - * See comments for XExpansion. - */ - - minExpand = cavityHeight; - numExpand = 0; - for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { - childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw - + slavePtr->padY + slavePtr->iPadY; - if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) { - curExpand = (cavityHeight - childHeight)/numExpand; - if (curExpand < minExpand) { - minExpand = curExpand; - } - } else { - cavityHeight -= childHeight; - if (slavePtr->flags & EXPAND) { - numExpand++; - } - } - } - curExpand = cavityHeight/numExpand; - if (curExpand < minExpand) { - minExpand = curExpand; - } - return (minExpand < 0) ? 0 : minExpand; -} - -/* - *-------------------------------------------------------------- - * - * GetPacker -- - * - * This internal procedure is used to locate a Packer - * structure for a given window, creating one if one - * doesn't exist already. - * - * Results: - * The return value is a pointer to the Packer structure - * corresponding to tkwin. - * - * Side effects: - * A new packer structure may be created. If so, then - * a callback is set up to clean things up when the - * window is deleted. - * - *-------------------------------------------------------------- - */ - -static Packer * -GetPacker(tkwin) - Tk_Window tkwin; /* Token for window for which - * packer structure is desired. */ -{ - register Packer *packPtr; - Tcl_HashEntry *hPtr; - int new; - - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&packerHashTable, TCL_ONE_WORD_KEYS); - } - - /* - * See if there's already packer for this window. If not, - * then create a new one. - */ - - hPtr = Tcl_CreateHashEntry(&packerHashTable, (char *) tkwin, &new); - if (!new) { - return (Packer *) Tcl_GetHashValue(hPtr); - } - packPtr = (Packer *) ckalloc(sizeof(Packer)); - packPtr->tkwin = tkwin; - packPtr->masterPtr = NULL; - packPtr->nextPtr = NULL; - packPtr->slavePtr = NULL; - packPtr->side = TOP; - packPtr->anchor = TK_ANCHOR_CENTER; - packPtr->padX = packPtr->padY = 0; - packPtr->iPadX = packPtr->iPadY = 0; - packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width; - packPtr->abortPtr = NULL; - packPtr->flags = 0; - Tcl_SetHashValue(hPtr, packPtr); - Tk_CreateEventHandler(tkwin, StructureNotifyMask, - PackStructureProc, (ClientData) packPtr); - return packPtr; -} - -/* - *-------------------------------------------------------------- - * - * PackAfter -- - * - * This procedure does most of the real work of adding - * one or more windows into the packing order for its parent. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * The geometry of the specified windows may change, both now and - * again in the future. - * - *-------------------------------------------------------------- - */ - -static int -PackAfter(interp, prevPtr, masterPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Packer *prevPtr; /* Pack windows in argv just after this - * window; NULL means pack as first - * child of masterPtr. */ - Packer *masterPtr; /* Master in which to pack windows. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Array of lists, each containing 2 - * elements: window name and side - * against which to pack. */ -{ - register Packer *packPtr; - Tk_Window tkwin, ancestor, parent; - size_t length; - char **options; - int index, tmp, optionCount, c; - - /* - * Iterate over all of the window specifiers, each consisting of - * two arguments. The first argument contains the window name and - * the additional arguments contain options such as "top" or - * "padx 20". - */ - - for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) { - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: window \"", - argv[0], "\" should be followed by options", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Find the packer for the window to be packed, and make sure - * that the window in which it will be packed is either its - * or a descendant of its parent. - */ - - tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - - parent = Tk_Parent(tkwin); - for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { - if (ancestor == parent) { - break; - } - if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) { - badWindow: - Tcl_AppendResult(interp, "can't pack ", argv[0], - " inside ", Tk_PathName(masterPtr->tkwin), - (char *) NULL); - return TCL_ERROR; - } - } - if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) { - goto badWindow; - } - if (tkwin == masterPtr->tkwin) { - goto badWindow; - } - packPtr = GetPacker(tkwin); - - /* - * Process options for this window. - */ - - if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) { - return TCL_ERROR; - } - packPtr->side = TOP; - packPtr->anchor = TK_ANCHOR_CENTER; - packPtr->padX = packPtr->padY = 0; - packPtr->iPadX = packPtr->iPadY = 0; - packPtr->flags &= ~(FILLX|FILLY|EXPAND); - packPtr->flags |= OLD_STYLE; - for (index = 0 ; index < optionCount; index++) { - char *curOpt = options[index]; - - c = curOpt[0]; - length = strlen(curOpt); - - if ((c == 't') - && (strncmp(curOpt, "top", length)) == 0) { - packPtr->side = TOP; - } else if ((c == 'b') - && (strncmp(curOpt, "bottom", length)) == 0) { - packPtr->side = BOTTOM; - } else if ((c == 'l') - && (strncmp(curOpt, "left", length)) == 0) { - packPtr->side = LEFT; - } else if ((c == 'r') - && (strncmp(curOpt, "right", length)) == 0) { - packPtr->side = RIGHT; - } else if ((c == 'e') - && (strncmp(curOpt, "expand", length)) == 0) { - packPtr->flags |= EXPAND; - } else if ((c == 'f') - && (strcmp(curOpt, "fill")) == 0) { - packPtr->flags |= FILLX|FILLY; - } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) { - packPtr->flags |= FILLX; - } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) { - packPtr->flags |= FILLY; - } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) { - if (optionCount < (index+2)) { - missingPad: - Tcl_AppendResult(interp, "wrong # args: \"", curOpt, - "\" option must be followed by screen distance", - (char *) NULL); - goto error; - } - if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp) - != TCL_OK) || (tmp < 0)) { - badPad: - Tcl_AppendResult(interp, "bad pad value \"", - options[index+1], - "\": must be positive screen distance", - (char *) NULL); - goto error; - } - packPtr->padX = tmp; - packPtr->iPadX = 0; - index++; - } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) { - if (optionCount < (index+2)) { - goto missingPad; - } - if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp) - != TCL_OK) || (tmp < 0)) { - goto badPad; - } - packPtr->padY = tmp; - packPtr->iPadY = 0; - index++; - } else if ((c == 'f') && (length > 1) - && (strncmp(curOpt, "frame", length) == 0)) { - if (optionCount < (index+2)) { - Tcl_AppendResult(interp, "wrong # args: \"frame\" ", - "option must be followed by anchor point", - (char *) NULL); - goto error; - } - if (Tk_GetAnchor(interp, options[index+1], - &packPtr->anchor) != TCL_OK) { - goto error; - } - index++; - } else { - Tcl_AppendResult(interp, "bad option \"", curOpt, - "\": should be top, bottom, left, right, ", - "expand, fill, fillx, filly, padx, pady, or frame", - (char *) NULL); - goto error; - } - } - - if (packPtr != prevPtr) { - - /* - * Unpack this window if it's currently packed. - */ - - if (packPtr->masterPtr != NULL) { - if ((packPtr->masterPtr != masterPtr) && - (packPtr->masterPtr->tkwin - != Tk_Parent(packPtr->tkwin))) { - Tk_UnmaintainGeometry(packPtr->tkwin, - packPtr->masterPtr->tkwin); - } - Unlink(packPtr); - } - - /* - * Add the window in the correct place in its parent's - * packing order, then make sure that the window is - * managed by us. - */ - - packPtr->masterPtr = masterPtr; - if (prevPtr == NULL) { - packPtr->nextPtr = masterPtr->slavePtr; - masterPtr->slavePtr = packPtr; - } else { - packPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = packPtr; - } - Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr); - } - ckfree((char *) options); - } - - /* - * Arrange for the parent to be re-packed at the first - * idle moment. - */ - - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_REPACK)) { - masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); - } - return TCL_OK; - - error: - ckfree((char *) options); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * Unlink -- - * - * Remove a packer from its parent's list of slaves. - * - * Results: - * None. - * - * Side effects: - * The parent will be scheduled for repacking. - * - *---------------------------------------------------------------------- - */ - -static void -Unlink(packPtr) - register Packer *packPtr; /* Window to unlink. */ -{ - register Packer *masterPtr, *packPtr2; - - masterPtr = packPtr->masterPtr; - if (masterPtr == NULL) { - return; - } - if (masterPtr->slavePtr == packPtr) { - masterPtr->slavePtr = packPtr->nextPtr; - } else { - for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) { - if (packPtr2 == NULL) { - panic("Unlink couldn't find previous window"); - } - if (packPtr2->nextPtr == packPtr) { - packPtr2->nextPtr = packPtr->nextPtr; - break; - } - } - } - if (!(masterPtr->flags & REQUESTED_REPACK)) { - masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); - } - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - - packPtr->masterPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyPacker -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a packer at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the packer is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyPacker(memPtr) - char *memPtr; /* Info about packed window that - * is now dead. */ -{ - register Packer *packPtr = (Packer *) memPtr; - ckfree((char *) packPtr); -} - -/* - *---------------------------------------------------------------------- - * - * PackStructureProc -- - * - * This procedure is invoked by the Tk event dispatcher in response - * to StructureNotify events. - * - * Results: - * None. - * - * Side effects: - * If a window was just deleted, clean up all its packer-related - * information. If it was just resized, repack its slaves, if - * any. - * - *---------------------------------------------------------------------- - */ - -static void -PackStructureProc(clientData, eventPtr) - ClientData clientData; /* Our information about window - * referred to by eventPtr. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - register Packer *packPtr = (Packer *) clientData; - if (eventPtr->type == ConfigureNotify) { - if ((packPtr->slavePtr != NULL) - && !(packPtr->flags & REQUESTED_REPACK)) { - packPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); - } - if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) { - if ((packPtr->masterPtr != NULL) - && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) { - packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width; - packPtr->masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr); - } - } - } else if (eventPtr->type == DestroyNotify) { - register Packer *slavePtr, *nextPtr; - - if (packPtr->masterPtr != NULL) { - Unlink(packPtr); - } - for (slavePtr = packPtr->slavePtr; slavePtr != NULL; - slavePtr = nextPtr) { - Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - Tk_UnmapWindow(slavePtr->tkwin); - slavePtr->masterPtr = NULL; - nextPtr = slavePtr->nextPtr; - slavePtr->nextPtr = NULL; - } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&packerHashTable, - (char *) packPtr->tkwin)); - if (packPtr->flags & REQUESTED_REPACK) { - Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr); - } - packPtr->tkwin = NULL; - Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker); - } else if (eventPtr->type == MapNotify) { - /* - * When a master gets mapped, must redo the geometry computation - * so that all of its slaves get remapped. - */ - - if ((packPtr->slavePtr != NULL) - && !(packPtr->flags & REQUESTED_REPACK)) { - packPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); - } - } else if (eventPtr->type == UnmapNotify) { - Packer *packPtr2; - - /* - * Unmap all of the slaves when the master gets unmapped, - * so that they don't bother to keep redisplaying - * themselves. - */ - - for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL; - packPtr2 = packPtr2->nextPtr) { - Tk_UnmapWindow(packPtr2->tkwin); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureSlaves -- - * - * This implements the guts of the "pack configure" command. Given - * a list of slaves and configuration options, it arranges for the - * packer to manage the slaves and sets the specified options. - * - * Results: - * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is - * returned and interp->result is set to contain an error message. - * - * Side effects: - * Slave windows get taken over by the packer. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureSlaves(interp, tkwin, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Any window in application containing - * slaves. Used to look up slave names. */ - int argc; /* Number of elements in argv. */ - char *argv[]; /* Argument strings: contains one or more - * window names followed by any number - * of "option value" pairs. Caller must - * make sure that there is at least one - * window name. */ -{ - Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr; - Tk_Window other, slave, parent, ancestor; - int i, j, numWindows, c, tmp, positionGiven; - size_t length; - - /* - * Find out how many windows are specified. - */ - - for (numWindows = 0; numWindows < argc; numWindows++) { - if (argv[numWindows][0] != '.') { - break; - } - } - - /* - * Iterate over all of the slave windows, parsing the configuration - * options for each slave. It's a bit wasteful to re-parse the - * options for each slave, but things get too messy if we try to - * parse the arguments just once at the beginning. For example, - * if a slave already is packed we want to just change a few - * existing values without resetting everything. If there are - * multiple windows, the -after, -before, and -in options only - * get processed for the first window. - */ - - masterPtr = NULL; - prevPtr = NULL; - positionGiven = 0; - for (j = 0; j < numWindows; j++) { - slave = Tk_NameToWindow(interp, argv[j], tkwin); - if (slave == NULL) { - return TCL_ERROR; - } - if (Tk_IsTopLevel(slave)) { - Tcl_AppendResult(interp, "can't pack \"", argv[j], - "\": it's a top-level window", (char *) NULL); - return TCL_ERROR; - } - slavePtr = GetPacker(slave); - slavePtr->flags &= ~OLD_STYLE; - - /* - * If the slave isn't currently packed, reset all of its - * configuration information to default values (there could - * be old values left from a previous packing). - */ - - if (slavePtr->masterPtr == NULL) { - slavePtr->side = TOP; - slavePtr->anchor = TK_ANCHOR_CENTER; - slavePtr->padX = slavePtr->padY = 0; - slavePtr->iPadX = slavePtr->iPadY = 0; - slavePtr->flags &= ~(FILLX|FILLY|EXPAND); - } - - for (i = numWindows; i < argc; i+=2) { - if ((i+2) > argc) { - Tcl_AppendResult(interp, "extra option \"", argv[i], - "\" (option with no value?)", (char *) NULL); - return TCL_ERROR; - } - length = strlen(argv[i]); - if (length < 2) { - goto badOption; - } - c = argv[i][1]; - if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0) - && (length >= 2)) { - if (j == 0) { - other = Tk_NameToWindow(interp, argv[i+1], tkwin); - if (other == NULL) { - return TCL_ERROR; - } - prevPtr = GetPacker(other); - if (prevPtr->masterPtr == NULL) { - notPacked: - Tcl_AppendResult(interp, "window \"", argv[i+1], - "\" isn't packed", (char *) NULL); - return TCL_ERROR; - } - masterPtr = prevPtr->masterPtr; - positionGiven = 1; - } - } else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0) - && (length >= 2)) { - if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor) - != TCL_OK) { - return TCL_ERROR; - } - } else if ((c == 'b') - && (strncmp(argv[i], "-before", length) == 0)) { - if (j == 0) { - other = Tk_NameToWindow(interp, argv[i+1], tkwin); - if (other == NULL) { - return TCL_ERROR; - } - otherPtr = GetPacker(other); - if (otherPtr->masterPtr == NULL) { - goto notPacked; - } - masterPtr = otherPtr->masterPtr; - prevPtr = masterPtr->slavePtr; - if (prevPtr == otherPtr) { - prevPtr = NULL; - } else { - while (prevPtr->nextPtr != otherPtr) { - prevPtr = prevPtr->nextPtr; - } - } - positionGiven = 1; - } - } else if ((c == 'e') - && (strncmp(argv[i], "-expand", length) == 0)) { - if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; - } - slavePtr->flags &= ~EXPAND; - if (tmp) { - slavePtr->flags |= EXPAND; - } - } else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) { - if (strcmp(argv[i+1], "none") == 0) { - slavePtr->flags &= ~(FILLX|FILLY); - } else if (strcmp(argv[i+1], "x") == 0) { - slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX; - } else if (strcmp(argv[i+1], "y") == 0) { - slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY; - } else if (strcmp(argv[i+1], "both") == 0) { - slavePtr->flags |= FILLX|FILLY; - } else { - Tcl_AppendResult(interp, "bad fill style \"", argv[i+1], - "\": must be none, x, y, or both", (char *) NULL); - return TCL_ERROR; - } - } else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) { - if (j == 0) { - other = Tk_NameToWindow(interp, argv[i+1], tkwin); - if (other == NULL) { - return TCL_ERROR; - } - masterPtr = GetPacker(other); - prevPtr = masterPtr->slavePtr; - if (prevPtr != NULL) { - while (prevPtr->nextPtr != NULL) { - prevPtr = prevPtr->nextPtr; - } - } - positionGiven = 1; - } - } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp < 0)) { - badPad: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad pad value \"", argv[i+1], - "\": must be positive screen distance", - (char *) NULL); - return TCL_ERROR; - } - slavePtr->iPadX = tmp*2; - } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - goto badPad; - } - slavePtr->iPadY = tmp*2; - } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - goto badPad; - } - slavePtr->padX = tmp*2; - } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) { - if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) - || (tmp< 0)) { - goto badPad; - } - slavePtr->padY = tmp*2; - } else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) { - c = argv[i+1][0]; - if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) { - slavePtr->side = TOP; - } else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) { - slavePtr->side = BOTTOM; - } else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) { - slavePtr->side = LEFT; - } else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) { - slavePtr->side = RIGHT; - } else { - Tcl_AppendResult(interp, "bad side \"", argv[i+1], - "\": must be top, bottom, left, or right", - (char *) NULL); - return TCL_ERROR; - } - } else { - badOption: - Tcl_AppendResult(interp, "unknown or ambiguous option \"", - argv[i], "\": must be -after, -anchor, -before, ", - "-expand, -fill, -in, -ipadx, -ipady, -padx, ", - "-pady, or -side", (char *) NULL); - return TCL_ERROR; - } - } - - /* - * If no position in a packing list was specified and the slave - * is already packed, then leave it in its current location in - * its current packing list. - */ - - if (!positionGiven && (slavePtr->masterPtr != NULL)) { - masterPtr = slavePtr->masterPtr; - goto scheduleLayout; - } - - /* - * If the slave is going to be put back after itself then - * skip the whole operation, since it won't work anyway. - */ - - if (prevPtr == slavePtr) { - masterPtr = slavePtr->masterPtr; - goto scheduleLayout; - } - - /* - * If none of the "-in", "-before", or "-after" options has - * been specified, arrange for the slave to go at the end of - * the order for its parent. - */ - - if (!positionGiven) { - masterPtr = GetPacker(Tk_Parent(slave)); - prevPtr = masterPtr->slavePtr; - if (prevPtr != NULL) { - while (prevPtr->nextPtr != NULL) { - prevPtr = prevPtr->nextPtr; - } - } - } - - /* - * Make sure that the slave's parent is either the master or - * an ancestor of the master, and that the master and slave - * aren't the same. - */ - - parent = Tk_Parent(slave); - for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { - if (ancestor == parent) { - break; - } - if (Tk_IsTopLevel(ancestor)) { - Tcl_AppendResult(interp, "can't pack ", argv[j], - " inside ", Tk_PathName(masterPtr->tkwin), - (char *) NULL); - return TCL_ERROR; - } - } - if (slave == masterPtr->tkwin) { - Tcl_AppendResult(interp, "can't pack ", argv[j], - " inside itself", (char *) NULL); - return TCL_ERROR; - } - - /* - * Unpack the slave if it's currently packed, then position it - * after prevPtr. - */ - - if (slavePtr->masterPtr != NULL) { - if ((slavePtr->masterPtr != masterPtr) && - (slavePtr->masterPtr->tkwin - != Tk_Parent(slavePtr->tkwin))) { - Tk_UnmaintainGeometry(slavePtr->tkwin, - slavePtr->masterPtr->tkwin); - } - Unlink(slavePtr); - } - slavePtr->masterPtr = masterPtr; - if (prevPtr == NULL) { - slavePtr->nextPtr = masterPtr->slavePtr; - masterPtr->slavePtr = slavePtr; - } else { - slavePtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = slavePtr; - } - Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr); - prevPtr = slavePtr; - - /* - * Arrange for the parent to be re-packed at the first - * idle moment. - */ - - scheduleLayout: - if (masterPtr->abortPtr != NULL) { - *masterPtr->abortPtr = 1; - } - if (!(masterPtr->flags & REQUESTED_REPACK)) { - masterPtr->flags |= REQUESTED_REPACK; - Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); - } - } - return TCL_OK; -} diff --git a/generic/tkPlace.c b/generic/tkPlace.c deleted file mode 100644 index 4e3784d..0000000 --- a/generic/tkPlace.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * tkPlace.c -- - * - * This file contains code to implement a simple geometry manager - * for Tk based on absolute placement or "rubber-sheet" placement. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkPlace.c,v 1.2 1998/09/14 18:23:15 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * Border modes for relative placement: - * - * BM_INSIDE: relative distances computed using area inside - * all borders of master window. - * BM_OUTSIDE: relative distances computed using outside area - * that includes all borders of master. - * BM_IGNORE: border issues are ignored: place relative to - * master's actual window size. - */ - -typedef enum {BM_INSIDE, BM_OUTSIDE, BM_IGNORE} BorderMode; - -/* - * For each window whose geometry is managed by the placer there is - * a structure of the following type: - */ - -typedef struct Slave { - Tk_Window tkwin; /* Tk's token for window. */ - struct Master *masterPtr; /* Pointer to information for window - * relative to which tkwin is placed. - * This isn't necessarily the logical - * parent of tkwin. NULL means the - * master was deleted or never assigned. */ - struct Slave *nextPtr; /* Next in list of windows placed relative - * to same master (NULL for end of list). */ - - /* - * Geometry information for window; where there are both relative - * and absolute values for the same attribute (e.g. x and relX) only - * one of them is actually used, depending on flags. - */ - - int x, y; /* X and Y pixel coordinates for tkwin. */ - float relX, relY; /* X and Y coordinates relative to size of - * master. */ - int width, height; /* Absolute dimensions for tkwin. */ - float relWidth, relHeight; /* Dimensions for tkwin relative to size of - * master. */ - Tk_Anchor anchor; /* Which point on tkwin is placed at the - * given position. */ - BorderMode borderMode; /* How to treat borders of master window. */ - int flags; /* Various flags; see below for bit - * definitions. */ -} Slave; - -/* - * Flag definitions for Slave structures: - * - * CHILD_WIDTH - 1 means -width was specified; - * CHILD_REL_WIDTH - 1 means -relwidth was specified. - * CHILD_HEIGHT - 1 means -height was specified; - * CHILD_REL_HEIGHT - 1 means -relheight was specified. - */ - -#define CHILD_WIDTH 1 -#define CHILD_REL_WIDTH 2 -#define CHILD_HEIGHT 4 -#define CHILD_REL_HEIGHT 8 - -/* - * For each master window that has a slave managed by the placer there - * is a structure of the following form: - */ - -typedef struct Master { - Tk_Window tkwin; /* Tk's token for master window. */ - struct Slave *slavePtr; /* First in linked list of slaves - * placed relative to this master. */ - int flags; /* See below for bit definitions. */ -} Master; - -/* - * Flag definitions for masters: - * - * PARENT_RECONFIG_PENDING - 1 means that a call to RecomputePlacement - * is already pending via a Do_When_Idle handler. - */ - -#define PARENT_RECONFIG_PENDING 1 - -/* - * The hash tables below both use Tk_Window tokens as keys. They map - * from Tk_Windows to Slave and Master structures for windows, if they - * exist. - */ - -static int initialized = 0; -static Tcl_HashTable masterTable; -static Tcl_HashTable slaveTable; -/* - * The following structure is the official type record for the - * placer: - */ - -static void PlaceRequestProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void PlaceLostSlaveProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); - -static Tk_GeomMgr placerType = { - "place", /* name */ - PlaceRequestProc, /* requestProc */ - PlaceLostSlaveProc, /* lostSlaveProc */ -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void SlaveStructureProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int ConfigureSlave _ANSI_ARGS_((Tcl_Interp *interp, - Slave *slavePtr, int argc, char **argv)); -static Slave * FindSlave _ANSI_ARGS_((Tk_Window tkwin)); -static Master * FindMaster _ANSI_ARGS_((Tk_Window tkwin)); -static void MasterStructureProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void RecomputePlacement _ANSI_ARGS_((ClientData clientData)); -static void UnlinkSlave _ANSI_ARGS_((Slave *slavePtr)); - -/* - *-------------------------------------------------------------- - * - * Tk_PlaceCmd -- - * - * This procedure is invoked to process the "place" Tcl - * commands. See the user documentation for details on - * what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_PlaceCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin; - Slave *slavePtr; - Tcl_HashEntry *hPtr; - size_t length; - int c; - - /* - * Initialize, if that hasn't been done yet. - */ - - if (!initialized) { - Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS); - Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS); - initialized = 1; - } - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option|pathName args", (char *) NULL); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - - /* - * Handle special shortcut where window name is first argument. - */ - - if (c == '.') { - tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData); - if (tkwin == NULL) { - return TCL_ERROR; - } - slavePtr = FindSlave(tkwin); - return ConfigureSlave(interp, slavePtr, argc-2, argv+2); - } - - /* - * Handle more general case of option followed by window name followed - * by possible additional arguments. - */ - - tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); - if (tkwin == NULL) { - return TCL_ERROR; - } - if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { - if (argc < 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], - " configure pathName option value ?option value ...?\"", - (char *) NULL); - return TCL_ERROR; - } - slavePtr = FindSlave(tkwin); - return ConfigureSlave(interp, slavePtr, argc-3, argv+3); - } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " forget pathName\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); - if (hPtr == NULL) { - return TCL_OK; - } - slavePtr = (Slave *) Tcl_GetHashValue(hPtr); - if ((slavePtr->masterPtr != NULL) && - (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) { - Tk_UnmaintainGeometry(slavePtr->tkwin, - slavePtr->masterPtr->tkwin); - } - UnlinkSlave(slavePtr); - Tcl_DeleteHashEntry(hPtr); - Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, - (ClientData) slavePtr); - Tk_ManageGeometry(tkwin, (Tk_GeomMgr *) NULL, (ClientData) NULL); - Tk_UnmapWindow(tkwin); - ckfree((char *) slavePtr); - } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { - char buffer[50]; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " info pathName\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); - if (hPtr == NULL) { - return TCL_OK; - } - slavePtr = (Slave *) Tcl_GetHashValue(hPtr); - sprintf(buffer, "-x %d", slavePtr->x); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, " -relx %.4g", slavePtr->relX); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, " -y %d", slavePtr->y); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, " -rely %.4g", slavePtr->relY); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (slavePtr->flags & CHILD_WIDTH) { - sprintf(buffer, " -width %d", slavePtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } else { - Tcl_AppendResult(interp, " -width {}", (char *) NULL); - } - if (slavePtr->flags & CHILD_REL_WIDTH) { - sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } else { - Tcl_AppendResult(interp, " -relwidth {}", (char *) NULL); - } - if (slavePtr->flags & CHILD_HEIGHT) { - sprintf(buffer, " -height %d", slavePtr->height); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } else { - Tcl_AppendResult(interp, " -height {}", (char *) NULL); - } - if (slavePtr->flags & CHILD_REL_HEIGHT) { - sprintf(buffer, " -relheight %.4g", slavePtr->relHeight); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } else { - Tcl_AppendResult(interp, " -relheight {}", (char *) NULL); - } - - Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor), - (char *) NULL); - if (slavePtr->borderMode == BM_OUTSIDE) { - Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL); - } else if (slavePtr->borderMode == BM_IGNORE) { - Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL); - } - if ((slavePtr->masterPtr != NULL) - && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) { - Tcl_AppendResult(interp, " -in ", - Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL); - } - } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " slaves pathName\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin); - if (hPtr != NULL) { - Master *masterPtr; - masterPtr = (Master *) Tcl_GetHashValue(hPtr); - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin)); - } - } - } else { - Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], - "\": must be configure, forget, info, or slaves", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * FindSlave -- - * - * Given a Tk_Window token, find the Slave structure corresponding - * to that token (making a new one if necessary). - * - * Results: - * None. - * - * Side effects: - * A new Slave structure may be created. - * - *---------------------------------------------------------------------- - */ - -static Slave * -FindSlave(tkwin) - Tk_Window tkwin; /* Token for desired slave. */ -{ - Tcl_HashEntry *hPtr; - register Slave *slavePtr; - int new; - - hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new); - if (new) { - slavePtr = (Slave *) ckalloc(sizeof(Slave)); - slavePtr->tkwin = tkwin; - slavePtr->masterPtr = NULL; - slavePtr->nextPtr = NULL; - slavePtr->x = slavePtr->y = 0; - slavePtr->relX = slavePtr->relY = (float) 0.0; - slavePtr->width = slavePtr->height = 0; - slavePtr->relWidth = slavePtr->relHeight = (float) 0.0; - slavePtr->anchor = TK_ANCHOR_NW; - slavePtr->borderMode = BM_INSIDE; - slavePtr->flags = 0; - Tcl_SetHashValue(hPtr, slavePtr); - Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, - (ClientData) slavePtr); - Tk_ManageGeometry(tkwin, &placerType, (ClientData) slavePtr); - } else { - slavePtr = (Slave *) Tcl_GetHashValue(hPtr); - } - return slavePtr; -} - -/* - *---------------------------------------------------------------------- - * - * UnlinkSlave -- - * - * This procedure removes a slave window from the chain of slaves - * in its master. - * - * Results: - * None. - * - * Side effects: - * The slave list of slavePtr's master changes. - * - *---------------------------------------------------------------------- - */ - -static void -UnlinkSlave(slavePtr) - Slave *slavePtr; /* Slave structure to be unlinked. */ -{ - register Master *masterPtr; - register Slave *prevPtr; - - masterPtr = slavePtr->masterPtr; - if (masterPtr == NULL) { - return; - } - if (masterPtr->slavePtr == slavePtr) { - masterPtr->slavePtr = slavePtr->nextPtr; - } else { - for (prevPtr = masterPtr->slavePtr; ; - prevPtr = prevPtr->nextPtr) { - if (prevPtr == NULL) { - panic("UnlinkSlave couldn't find slave to unlink"); - } - if (prevPtr->nextPtr == slavePtr) { - prevPtr->nextPtr = slavePtr->nextPtr; - break; - } - } - } - slavePtr->masterPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * FindMaster -- - * - * Given a Tk_Window token, find the Master structure corresponding - * to that token (making a new one if necessary). - * - * Results: - * None. - * - * Side effects: - * A new Master structure may be created. - * - *---------------------------------------------------------------------- - */ - -static Master * -FindMaster(tkwin) - Tk_Window tkwin; /* Token for desired master. */ -{ - Tcl_HashEntry *hPtr; - register Master *masterPtr; - int new; - - hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new); - if (new) { - masterPtr = (Master *) ckalloc(sizeof(Master)); - masterPtr->tkwin = tkwin; - masterPtr->slavePtr = NULL; - masterPtr->flags = 0; - Tcl_SetHashValue(hPtr, masterPtr); - Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask, - MasterStructureProc, (ClientData) masterPtr); - } else { - masterPtr = (Master *) Tcl_GetHashValue(hPtr); - } - return masterPtr; -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureSlave -- - * - * This procedure is called to process an argv/argc list to - * reconfigure the placement of a window. - * - * Results: - * A standard Tcl result. If an error occurs then a message is - * left in interp->result. - * - * Side effects: - * Information in slavePtr may change, and slavePtr's master is - * scheduled for reconfiguration. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureSlave(interp, slavePtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Slave *slavePtr; /* Pointer to current information - * about slave. */ - int argc; /* Number of config arguments. */ - char **argv; /* String values for arguments. */ -{ - register Master *masterPtr; - int c, result; - size_t length; - double d; - - result = TCL_OK; - if (Tk_IsTopLevel(slavePtr->tkwin)) { - Tcl_AppendResult(interp, "can't use placer on top-level window \"", - Tk_PathName(slavePtr->tkwin), "\"; use wm command instead", - (char *) NULL); - return TCL_ERROR; - } - for ( ; argc > 0; argc -= 2, argv += 2) { - if (argc < 2) { - Tcl_AppendResult(interp, "extra option \"", argv[0], - "\" (option with no value?)", (char *) NULL); - result = TCL_ERROR; - goto done; - } - length = strlen(argv[0]); - c = argv[0][1]; - if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) { - if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - } else if ((c == 'b') - && (strncmp(argv[0], "-bordermode", length) == 0)) { - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0) - && (length >= 2)) { - slavePtr->borderMode = BM_IGNORE; - } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0) - && (length >= 2)) { - slavePtr->borderMode = BM_INSIDE; - } else if ((c == 'o') - && (strncmp(argv[1], "outside", length) == 0)) { - slavePtr->borderMode = BM_OUTSIDE; - } else { - Tcl_AppendResult(interp, "bad border mode \"", argv[1], - "\": must be ignore, inside, or outside", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) { - if (argv[1][0] == 0) { - slavePtr->flags &= ~CHILD_HEIGHT; - } else { - if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], - &slavePtr->height) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->flags |= CHILD_HEIGHT; - } - } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) { - Tk_Window tkwin; - Tk_Window ancestor; - - tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin); - if (tkwin == NULL) { - result = TCL_ERROR; - goto done; - } - - /* - * Make sure that the new master is either the logical parent - * of the slave or a descendant of that window, and that the - * master and slave aren't the same. - */ - - for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) { - if (ancestor == Tk_Parent(slavePtr->tkwin)) { - break; - } - if (Tk_IsTopLevel(ancestor)) { - Tcl_AppendResult(interp, "can't place ", - Tk_PathName(slavePtr->tkwin), " relative to ", - Tk_PathName(tkwin), (char *) NULL); - result = TCL_ERROR; - goto done; - } - } - if (slavePtr->tkwin == tkwin) { - Tcl_AppendResult(interp, "can't place ", - Tk_PathName(slavePtr->tkwin), " relative to itself", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - if ((slavePtr->masterPtr != NULL) - && (slavePtr->masterPtr->tkwin == tkwin)) { - /* - * Re-using same old master. Nothing to do. - */ - } else { - if ((slavePtr->masterPtr != NULL) - && (slavePtr->masterPtr->tkwin - != Tk_Parent(slavePtr->tkwin))) { - Tk_UnmaintainGeometry(slavePtr->tkwin, - slavePtr->masterPtr->tkwin); - } - UnlinkSlave(slavePtr); - slavePtr->masterPtr = FindMaster(tkwin); - slavePtr->nextPtr = slavePtr->masterPtr->slavePtr; - slavePtr->masterPtr->slavePtr = slavePtr; - } - } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0) - && (length >= 5)) { - if (argv[1][0] == 0) { - slavePtr->flags &= ~CHILD_REL_HEIGHT; - } else { - if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->relHeight = (float) d; - slavePtr->flags |= CHILD_REL_HEIGHT; - } - } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0) - && (length >= 5)) { - if (argv[1][0] == 0) { - slavePtr->flags &= ~CHILD_REL_WIDTH; - } else { - if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->relWidth = (float) d; - slavePtr->flags |= CHILD_REL_WIDTH; - } - } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0) - && (length >= 5)) { - if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->relX = (float) d; - } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0) - && (length >= 5)) { - if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->relY = (float) d; - } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) { - if (argv[1][0] == 0) { - slavePtr->flags &= ~CHILD_WIDTH; - } else { - if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], - &slavePtr->width) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - slavePtr->flags |= CHILD_WIDTH; - } - } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) { - if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], - &slavePtr->x) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) { - if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], - &slavePtr->y) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - } else { - Tcl_AppendResult(interp, "unknown or ambiguous option \"", - argv[0], "\": must be -anchor, -bordermode, -height, ", - "-in, -relheight, -relwidth, -relx, -rely, -width, ", - "-x, or -y", (char *) NULL); - result = TCL_ERROR; - goto done; - } - } - - /* - * If there's no master specified for this slave, use its Tk_Parent. - * Then arrange for a placement recalculation in the master. - */ - - done: - masterPtr = slavePtr->masterPtr; - if (masterPtr == NULL) { - masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin)); - slavePtr->masterPtr = masterPtr; - slavePtr->nextPtr = masterPtr->slavePtr; - masterPtr->slavePtr = slavePtr; - } - if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) { - masterPtr->flags |= PARENT_RECONFIG_PENDING; - Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * RecomputePlacement -- - * - * This procedure is called as a when-idle handler. It recomputes - * the geometries of all the slaves of a given master. - * - * Results: - * None. - * - * Side effects: - * Windows may change size or shape. - * - *---------------------------------------------------------------------- - */ - -static void -RecomputePlacement(clientData) - ClientData clientData; /* Pointer to Master record. */ -{ - register Master *masterPtr = (Master *) clientData; - register Slave *slavePtr; - int x, y, width, height, tmp; - int masterWidth, masterHeight, masterBW; - double x1, y1, x2, y2; - - masterPtr->flags &= ~PARENT_RECONFIG_PENDING; - - /* - * Iterate over all the slaves for the master. Each slave's - * geometry can be computed independently of the other slaves. - */ - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - /* - * Step 1: compute size and borderwidth of master, taking into - * account desired border mode. - */ - - masterBW = 0; - masterWidth = Tk_Width(masterPtr->tkwin); - masterHeight = Tk_Height(masterPtr->tkwin); - if (slavePtr->borderMode == BM_INSIDE) { - masterBW = Tk_InternalBorderWidth(masterPtr->tkwin); - } else if (slavePtr->borderMode == BM_OUTSIDE) { - masterBW = -Tk_Changes(masterPtr->tkwin)->border_width; - } - masterWidth -= 2*masterBW; - masterHeight -= 2*masterBW; - - /* - * Step 2: compute size of slave (outside dimensions including - * border) and location of anchor point within master. - */ - - x1 = slavePtr->x + masterBW + (slavePtr->relX*masterWidth); - x = (int) (x1 + ((x1 > 0) ? 0.5 : -0.5)); - y1 = slavePtr->y + masterBW + (slavePtr->relY*masterHeight); - y = (int) (y1 + ((y1 > 0) ? 0.5 : -0.5)); - if (slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) { - width = 0; - if (slavePtr->flags & CHILD_WIDTH) { - width += slavePtr->width; - } - if (slavePtr->flags & CHILD_REL_WIDTH) { - /* - * The code below is a bit tricky. In order to round - * correctly when both relX and relWidth are specified, - * compute the location of the right edge and round that, - * then compute width. If we compute the width and round - * it, rounding errors in relX and relWidth accumulate. - */ - - x2 = x1 + (slavePtr->relWidth*masterWidth); - tmp = (int) (x2 + ((x2 > 0) ? 0.5 : -0.5)); - width += tmp - x; - } - } else { - width = Tk_ReqWidth(slavePtr->tkwin) - + 2*Tk_Changes(slavePtr->tkwin)->border_width; - } - if (slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) { - height = 0; - if (slavePtr->flags & CHILD_HEIGHT) { - height += slavePtr->height; - } - if (slavePtr->flags & CHILD_REL_HEIGHT) { - /* - * See note above for rounding errors in width computation. - */ - - y2 = y1 + (slavePtr->relHeight*masterHeight); - tmp = (int) (y2 + ((y2 > 0) ? 0.5 : -0.5)); - height += tmp - y; - } - } else { - height = Tk_ReqHeight(slavePtr->tkwin) - + 2*Tk_Changes(slavePtr->tkwin)->border_width; - } - - /* - * Step 3: adjust the x and y positions so that the desired - * anchor point on the slave appears at that position. Also - * adjust for the border mode and master's border. - */ - - switch (slavePtr->anchor) { - case TK_ANCHOR_N: - x -= width/2; - break; - case TK_ANCHOR_NE: - x -= width; - break; - case TK_ANCHOR_E: - x -= width; - y -= height/2; - break; - case TK_ANCHOR_SE: - x -= width; - y -= height; - break; - case TK_ANCHOR_S: - x -= width/2; - y -= height; - break; - case TK_ANCHOR_SW: - y -= height; - break; - case TK_ANCHOR_W: - y -= height/2; - break; - case TK_ANCHOR_NW: - break; - case TK_ANCHOR_CENTER: - x -= width/2; - y -= height/2; - break; - } - - /* - * Step 4: adjust width and height again to reflect inside dimensions - * of window rather than outside. Also make sure that the width and - * height aren't zero. - */ - - width -= 2*Tk_Changes(slavePtr->tkwin)->border_width; - height -= 2*Tk_Changes(slavePtr->tkwin)->border_width; - if (width <= 0) { - width = 1; - } - if (height <= 0) { - height = 1; - } - - /* - * Step 5: reconfigure the window and map it if needed. If the - * slave is a child of the master, we do this ourselves. If the - * slave isn't a child of the master, let Tk_MaintainWindow do - * the work (it will re-adjust things as relevant windows map, - * unmap, and move). - */ - - if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) { - if ((x != Tk_X(slavePtr->tkwin)) - || (y != Tk_Y(slavePtr->tkwin)) - || (width != Tk_Width(slavePtr->tkwin)) - || (height != Tk_Height(slavePtr->tkwin))) { - Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height); - } - - /* - * Don't map the slave unless the master is mapped: the slave - * will get mapped later, when the master is mapped. - */ - - if (Tk_IsMapped(masterPtr->tkwin)) { - Tk_MapWindow(slavePtr->tkwin); - } - } else { - if ((width <= 0) || (height <= 0)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin); - Tk_UnmapWindow(slavePtr->tkwin); - } else { - Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin, - x, y, width, height); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * MasterStructureProc -- - * - * This procedure is invoked by the Tk event handler when - * StructureNotify events occur for a master window. - * - * Results: - * None. - * - * Side effects: - * Structures get cleaned up if the window was deleted. If the - * window was resized then slave geometries get recomputed. - * - *---------------------------------------------------------------------- - */ - -static void -MasterStructureProc(clientData, eventPtr) - ClientData clientData; /* Pointer to Master structure for window - * referred to by eventPtr. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - register Master *masterPtr = (Master *) clientData; - register Slave *slavePtr, *nextPtr; - - if (eventPtr->type == ConfigureNotify) { - if ((masterPtr->slavePtr != NULL) - && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) { - masterPtr->flags |= PARENT_RECONFIG_PENDING; - Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); - } - } else if (eventPtr->type == DestroyNotify) { - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = nextPtr) { - slavePtr->masterPtr = NULL; - nextPtr = slavePtr->nextPtr; - slavePtr->nextPtr = NULL; - } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable, - (char *) masterPtr->tkwin)); - if (masterPtr->flags & PARENT_RECONFIG_PENDING) { - Tcl_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr); - } - masterPtr->tkwin = NULL; - ckfree((char *) masterPtr); - } else if (eventPtr->type == MapNotify) { - /* - * When a master gets mapped, must redo the geometry computation - * so that all of its slaves get remapped. - */ - - if ((masterPtr->slavePtr != NULL) - && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) { - masterPtr->flags |= PARENT_RECONFIG_PENDING; - Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); - } - } else if (eventPtr->type == UnmapNotify) { - /* - * Unmap all of the slaves when the master gets unmapped, - * so that they don't keep redisplaying themselves. - */ - - for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; - slavePtr = slavePtr->nextPtr) { - Tk_UnmapWindow(slavePtr->tkwin); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * SlaveStructureProc -- - * - * This procedure is invoked by the Tk event handler when - * StructureNotify events occur for a slave window. - * - * Results: - * None. - * - * Side effects: - * Structures get cleaned up if the window was deleted. - * - *---------------------------------------------------------------------- - */ - -static void -SlaveStructureProc(clientData, eventPtr) - ClientData clientData; /* Pointer to Slave structure for window - * referred to by eventPtr. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - register Slave *slavePtr = (Slave *) clientData; - - if (eventPtr->type == DestroyNotify) { - UnlinkSlave(slavePtr); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable, - (char *) slavePtr->tkwin)); - ckfree((char *) slavePtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * PlaceRequestProc -- - * - * This procedure is invoked by Tk whenever a slave managed by us - * changes its requested geometry. - * - * Results: - * None. - * - * Side effects: - * The window will get relayed out, if its requested size has - * anything to do with its actual size. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -PlaceRequestProc(clientData, tkwin) - ClientData clientData; /* Pointer to our record for slave. */ - Tk_Window tkwin; /* Window that changed its desired - * size. */ -{ - Slave *slavePtr = (Slave *) clientData; - Master *masterPtr; - - if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0) - && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) { - return; - } - masterPtr = slavePtr->masterPtr; - if (masterPtr == NULL) { - return; - } - if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) { - masterPtr->flags |= PARENT_RECONFIG_PENDING; - Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * PlaceLostSlaveProc -- - * - * This procedure is invoked by Tk whenever some other geometry - * claims control over a slave that used to be managed by us. - * - * Results: - * None. - * - * Side effects: - * Forgets all placer-related information about the slave. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -PlaceLostSlaveProc(clientData, tkwin) - ClientData clientData; /* Slave structure for slave window that - * was stolen away. */ - Tk_Window tkwin; /* Tk's handle for the slave window. */ -{ - register Slave *slavePtr = (Slave *) clientData; - - if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { - Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); - } - Tk_UnmapWindow(tkwin); - UnlinkSlave(slavePtr); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable, (char *) tkwin)); - Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, - (ClientData) slavePtr); - ckfree((char *) slavePtr); -} diff --git a/generic/tkPointer.c b/generic/tkPointer.c deleted file mode 100644 index 1817914..0000000 --- a/generic/tkPointer.c +++ /dev/null @@ -1,623 +0,0 @@ -/* - * tkPointer.c -- - * - * This file contains functions for emulating the X server - * pointer and grab state machine. This file is used by the - * Mac and Windows platforms to generate appropriate enter/leave - * events, and to update the global grab window information. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkPointer.c,v 1.2 1998/09/14 18:23:16 stanton Exp $ - */ - -#include "tkInt.h" - -#ifdef MAC_TCL -#define Cursor XCursor -#endif - -/* - * Mask that selects any of the state bits corresponding to buttons, - * plus masks that select individual buttons' bits: - */ - -#define ALL_BUTTONS \ - (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) -static unsigned int buttonMasks[] = { - Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask -}; -#define ButtonMask(b) (buttonMasks[(b)-Button1]) - -/* - * Declarations of static variables used in the pointer module. - */ - -static TkWindow *cursorWinPtr = NULL; /* Window that is currently - * controlling the global cursor. */ -static TkWindow *grabWinPtr = NULL; /* Window that defines the top of the - * grab tree in a global grab. */ -static XPoint lastPos = { 0, 0}; /* Last reported mouse position. */ -static int lastState = 0; /* Last known state flags. */ -static TkWindow *lastWinPtr = NULL; /* Last reported mouse window. */ -static TkWindow *restrictWinPtr = NULL; /* Window to which all mouse events - * will be reported. */ - -/* - * Forward declarations of procedures used in this file. - */ - -static int GenerateEnterLeave _ANSI_ARGS_((TkWindow *winPtr, - int x, int y, int state)); -static void InitializeEvent _ANSI_ARGS_((XEvent* eventPtr, - TkWindow *winPtr, int type, int x, int y, - int state, int detail)); -static void UpdateCursor _ANSI_ARGS_((TkWindow *winPtr)); - -/* - *---------------------------------------------------------------------- - * - * InitializeEvent -- - * - * Initializes the common fields for several X events. - * - * Results: - * None. - * - * Side effects: - * Fills in the specified event structure. - * - *---------------------------------------------------------------------- - */ - -static void -InitializeEvent(eventPtr, winPtr, type, x, y, state, detail) - XEvent* eventPtr; /* Event structure to initialize. */ - TkWindow *winPtr; /* Window to make event relative to. */ - int type; /* Message type. */ - int x, y; /* Root coords of event. */ - int state; /* State flags. */ - int detail; /* Detail value. */ -{ - eventPtr->type = type; - eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display); - eventPtr->xany.send_event = False; - eventPtr->xany.display = winPtr->display; - - eventPtr->xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum); - eventPtr->xcrossing.time = TkpGetMS(); - eventPtr->xcrossing.x_root = x; - eventPtr->xcrossing.y_root = y; - - switch (type) { - case EnterNotify: - case LeaveNotify: - eventPtr->xcrossing.mode = NotifyNormal; - eventPtr->xcrossing.state = state; - eventPtr->xcrossing.detail = detail; - eventPtr->xcrossing.focus = False; - break; - case MotionNotify: - eventPtr->xmotion.state = state; - eventPtr->xmotion.is_hint = detail; - break; - case ButtonPress: - case ButtonRelease: - eventPtr->xbutton.state = state; - eventPtr->xbutton.button = detail; - break; - } - TkChangeEventWindow(eventPtr, winPtr); -} - -/* - *---------------------------------------------------------------------- - * - * GenerateEnterLeave -- - * - * Update the current mouse window and position, and generate - * any enter/leave events that are needed. - * - * Results: - * Returns 1 if enter/leave events were generated. - * - * Side effects: - * May insert events into the Tk event queue. - * - *---------------------------------------------------------------------- - */ - -static int -GenerateEnterLeave(winPtr, x, y, state) - TkWindow *winPtr; /* Current Tk window (or NULL). */ - int x,y; /* Current mouse position in root coords. */ - int state; /* State flags. */ -{ - int crossed = 0; /* 1 if mouse crossed a window boundary */ - - if (winPtr != lastWinPtr) { - if (restrictWinPtr) { - int newPos, oldPos; - - newPos = TkPositionInTree(winPtr, restrictWinPtr); - oldPos = TkPositionInTree(lastWinPtr, restrictWinPtr); - - /* - * Check if the mouse crossed into or out of the restrict - * window. If so, we need to generate an Enter or Leave event. - */ - - if ((newPos != oldPos) && ((newPos == TK_GRAB_IN_TREE) - || (oldPos == TK_GRAB_IN_TREE))) { - XEvent event; - int type, detail; - - if (newPos == TK_GRAB_IN_TREE) { - type = EnterNotify; - } else { - type = LeaveNotify; - } - if ((oldPos == TK_GRAB_ANCESTOR) - || (newPos == TK_GRAB_ANCESTOR)) { - detail = NotifyAncestor; - } else { - detail = NotifyVirtual; - } - InitializeEvent(&event, restrictWinPtr, type, x, y, - state, detail); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - } - - } else { - TkWindow *targetPtr; - - if ((lastWinPtr == NULL) - || (lastWinPtr->window == None)) { - targetPtr = winPtr; - } else { - targetPtr = lastWinPtr; - } - - if (targetPtr && (targetPtr->window != None)) { - XEvent event; - - /* - * Generate appropriate Enter/Leave events. - */ - - InitializeEvent(&event, targetPtr, LeaveNotify, x, y, state, - NotifyNormal); - - TkInOutEvents(&event, lastWinPtr, winPtr, LeaveNotify, - EnterNotify, TCL_QUEUE_TAIL); - crossed = 1; - } - } - lastWinPtr = winPtr; - } - - return crossed; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_UpdatePointer -- - * - * This function updates the pointer state machine given an - * the current window, position and modifier state. - * - * Results: - * None. - * - * Side effects: - * May queue new events and update the grab state. - * - *---------------------------------------------------------------------- - */ - -void -Tk_UpdatePointer(tkwin, x, y, state) - Tk_Window tkwin; /* Window to which pointer event - * is reported. May be NULL. */ - int x, y; /* Pointer location in root coords. */ - int state; /* Modifier state mask. */ -{ - TkWindow *winPtr = (TkWindow *)tkwin; - TkWindow *targetWinPtr; - XPoint pos; - XEvent event; - int changes = (state ^ lastState) & ALL_BUTTONS; - int type, b, mask; - - pos.x = x; - pos.y = y; - - /* - * Use the current keyboard state, but the old mouse button - * state since we haven't generated the button events yet. - */ - - lastState = (state & ~ALL_BUTTONS) | (lastState & ALL_BUTTONS); - - /* - * Generate Enter/Leave events. If the pointer has crossed window - * boundaries, update the current mouse position so we don't generate - * redundant motion events. - */ - - if (GenerateEnterLeave(winPtr, x, y, lastState)) { - lastPos = pos; - } - - /* - * Generate ButtonPress/ButtonRelease events based on the differences - * between the current button state and the last known button state. - */ - - for (b = Button1; b <= Button3; b++) { - mask = ButtonMask(b); - if (changes & mask) { - if (state & mask) { - type = ButtonPress; - - /* - * ButtonPress - Set restrict window if we aren't grabbed, or - * if this is the first button down. - */ - - if (!restrictWinPtr) { - if (!grabWinPtr) { - - /* - * Mouse is not grabbed, so set a button grab. - */ - - restrictWinPtr = winPtr; - TkpSetCapture(restrictWinPtr); - - } else if ((lastState & ALL_BUTTONS) == 0) { - - /* - * Mouse is in a non-button grab, so ensure - * the button grab is inside the grab tree. - */ - - if (TkPositionInTree(winPtr, grabWinPtr) - == TK_GRAB_IN_TREE) { - restrictWinPtr = winPtr; - } else { - restrictWinPtr = grabWinPtr; - } - TkpSetCapture(restrictWinPtr); - } - } - - } else { - type = ButtonRelease; - - /* - * ButtonRelease - Release the mouse capture and clear the - * restrict window when the last button is released and we - * aren't in a global grab. - */ - - if ((lastState & ALL_BUTTONS) == mask) { - if (!grabWinPtr) { - TkpSetCapture(NULL); - } - } - - /* - * If we are releasing a restrict window, then we need - * to send the button event followed by mouse motion from - * the restrict window to the current mouse position. - */ - - if (restrictWinPtr) { - InitializeEvent(&event, restrictWinPtr, type, x, y, - lastState, b); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - lastState &= ~mask; - lastWinPtr = restrictWinPtr; - restrictWinPtr = NULL; - - GenerateEnterLeave(winPtr, x, y, lastState); - lastPos = pos; - continue; - } - } - - /* - * If a restrict window is set, make sure the pointer event - * is reported relative to that window. Otherwise, if a - * global grab is in effect then events outside of windows - * managed by Tk should be reported to the grab window. - */ - - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr && !winPtr) { - targetWinPtr = grabWinPtr; - } else { - targetWinPtr = winPtr; - } - - /* - * If we still have a target window, send the event. - */ - - if (winPtr != NULL) { - InitializeEvent(&event, targetWinPtr, type, x, y, - lastState, b); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - } - - /* - * Update the state for the next iteration. - */ - - lastState = (type == ButtonPress) - ? (lastState | mask) : (lastState & ~mask); - lastPos = pos; - } - } - - /* - * Make sure the cursor window is up to date. - */ - - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr) { - targetWinPtr = (TkPositionInTree(winPtr, grabWinPtr) - == TK_GRAB_IN_TREE) ? winPtr : grabWinPtr; - } else { - targetWinPtr = winPtr; - } - UpdateCursor(targetWinPtr); - - /* - * If no other events caused the position to be updated, - * generate a motion event. - */ - - if (lastPos.x != pos.x || lastPos.y != pos.y) { - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr && !winPtr) { - targetWinPtr = grabWinPtr; - } - - if (targetWinPtr != NULL) { - InitializeEvent(&event, targetWinPtr, MotionNotify, x, y, - lastState, NotifyNormal); - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - } - lastPos = pos; - } -} - -/* - *---------------------------------------------------------------------- - * - * XGrabPointer -- - * - * Capture the mouse so event are reported outside of toplevels. - * Note that this is a very limited implementation that only - * supports GrabModeAsync and owner_events True. - * - * Results: - * Always returns GrabSuccess. - * - * Side effects: - * Turns on mouse capture, sets the global grab pointer, and - * clears any window restrictions. - * - *---------------------------------------------------------------------- - */ - -int -XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, - keyboard_mode, confine_to, cursor, time) - Display* display; - Window grab_window; - Bool owner_events; - unsigned int event_mask; - int pointer_mode; - int keyboard_mode; - Window confine_to; - Cursor cursor; - Time time; -{ - display->request++; - grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window); - restrictWinPtr = NULL; - TkpSetCapture(grabWinPtr); - if (TkPositionInTree(lastWinPtr, grabWinPtr) != TK_GRAB_IN_TREE) { - UpdateCursor(grabWinPtr); - } - return GrabSuccess; -} - -/* - *---------------------------------------------------------------------- - * - * XUngrabPointer -- - * - * Release the current grab. - * - * Results: - * None. - * - * Side effects: - * Releases the mouse capture. - * - *---------------------------------------------------------------------- - */ - -void -XUngrabPointer(display, time) - Display* display; - Time time; -{ - display->request++; - grabWinPtr = NULL; - restrictWinPtr = NULL; - TkpSetCapture(NULL); - UpdateCursor(lastWinPtr); -} - -/* - *---------------------------------------------------------------------- - * - * TkPointerDeadWindow -- - * - * Clean up pointer module state when a window is destroyed. - * - * Results: - * None. - * - * Side effects: - * May release the current capture window. - * - *---------------------------------------------------------------------- - */ - -void -TkPointerDeadWindow(winPtr) - TkWindow *winPtr; -{ - if (winPtr == lastWinPtr) { - lastWinPtr = NULL; - } - if (winPtr == grabWinPtr) { - grabWinPtr = NULL; - } - if (winPtr == restrictWinPtr) { - restrictWinPtr = NULL; - } - if (!(restrictWinPtr || grabWinPtr)) { - TkpSetCapture(NULL); - } -} - -/* - *---------------------------------------------------------------------- - * - * UpdateCursor -- - * - * Set the windows global cursor to the cursor associated with - * the given Tk window. - * - * Results: - * None. - * - * Side effects: - * Changes the mouse cursor. - * - *---------------------------------------------------------------------- - */ - -static void -UpdateCursor(winPtr) - TkWindow *winPtr; -{ - Cursor cursor = None; - - /* - * A window inherits its cursor from its parent if it doesn't - * have one of its own. Top level windows inherit the default - * cursor. - */ - - cursorWinPtr = winPtr; - while (winPtr != NULL) { - if (winPtr->atts.cursor != None) { - cursor = winPtr->atts.cursor; - break; - } else if (winPtr->flags & TK_TOP_LEVEL) { - break; - } - winPtr = winPtr->parentPtr; - } - TkpSetCursor((TkpCursor) cursor); -} - -/* - *---------------------------------------------------------------------- - * - * XDefineCursor -- - * - * This function is called to update the cursor on a window. - * Since the mouse might be in the specified window, we need to - * check the specified window against the current mouse position - * and grab state. - * - * Results: - * None. - * - * Side effects: - * May update the cursor. - * - *---------------------------------------------------------------------- - */ - -void -XDefineCursor(display, w, cursor) - Display* display; - Window w; - Cursor cursor; -{ - TkWindow *winPtr = (TkWindow *)Tk_IdToWindow(display, w); - - if (cursorWinPtr == winPtr) { - UpdateCursor(winPtr); - } - display->request++; -} - -/* - *---------------------------------------------------------------------- - * - * TkGenerateActivateEvents -- - * - * This function is called by the Mac and Windows window manager - * routines when a toplevel window is activated or deactivated. - * Activate/Deactivate events will be sent to every subwindow of - * the toplevel followed by a FocusIn/FocusOut message. - * - * Results: - * None. - * - * Side effects: - * Generates X events. - * - *---------------------------------------------------------------------- - */ - -void -TkGenerateActivateEvents(winPtr, active) - TkWindow *winPtr; /* Toplevel to activate. */ - int active; /* Non-zero if the window is being - * activated, else 0.*/ -{ - XEvent event; - - /* - * Generate Activate and Deactivate events. This event - * is sent to every subwindow in a toplevel window. - */ - - event.xany.serial = winPtr->display->request++; - event.xany.send_event = False; - event.xany.display = winPtr->display; - event.xany.window = winPtr->window; - - event.xany.type = active ? ActivateNotify : DeactivateNotify; - TkQueueEventForAllChildren(winPtr, &event); - -} diff --git a/generic/tkPort.h b/generic/tkPort.h deleted file mode 100644 index 04e1dab..0000000 --- a/generic/tkPort.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * tkPort.h -- - * - * This header file handles porting issues that occur because of - * differences between systems. It reads in platform specific - * portability files. - * - * Copyright (c) 1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkPort.h,v 1.2 1998/09/14 18:23:16 stanton Exp $ - */ - -#ifndef _TKPORT -#define _TKPORT - -#ifndef _TK -#include "tk.h" -#endif -#ifndef _TCL -#include "tcl.h" -#endif - -#if defined(__WIN32__) || defined(_WIN32) -# include "tkWinPort.h" -#else -# if defined(MAC_TCL) -# include "tkMacPort.h" -# else -# include "../unix/tkUnixPort.h" -# endif -#endif - -#endif /* _TKPORT */ diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c deleted file mode 100644 index beba5a0..0000000 --- a/generic/tkRectOval.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * tkRectOval.c -- - * - * This file implements rectangle and oval items for canvas - * widgets. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkRectOval.c,v 1.2 1998/09/14 18:23:16 stanton Exp $ - */ - -#include <stdio.h> -#include "tk.h" -#include "tkInt.h" -#include "tkPort.h" - -/* - * The structure below defines the record for each rectangle/oval item. - */ - -typedef struct RectOvalItem { - Tk_Item header; /* Generic stuff that's the same for all - * types. MUST BE FIRST IN STRUCTURE. */ - double bbox[4]; /* Coordinates of bounding box for rectangle - * or oval (x1, y1, x2, y2). Item includes - * x1 and x2 but not y1 and y2. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ - XColor *fillColor; /* Color for filling rectangle/oval. */ - Pixmap fillStipple; /* Stipple bitmap for filling item. */ - GC outlineGC; /* Graphics context for outline. */ - GC fillGC; /* Graphics context for filling item. */ -} RectOvalItem; - -/* - * Information used for parsing configuration specs: - */ - -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL -}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, - (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Prototypes for procedures defined in this file: - */ - -static void ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas canvas, - RectOvalItem *rectOvalPtr)); -static int ConfigureRectOval _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int CreateRectOval _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); -static void DeleteRectOval _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display)); -static void DisplayRectOval _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, Display *display, Drawable dst, - int x, int y, int width, int height)); -static int OvalToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *areaPtr)); -static double OvalToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); -static int RectOvalCoords _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); -static int RectOvalToPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); -static int RectToArea _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *areaPtr)); -static double RectToPoint _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double *pointPtr)); -static void ScaleRectOval _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double originX, double originY, - double scaleX, double scaleY)); -static void TranslateRectOval _ANSI_ARGS_((Tk_Canvas canvas, - Tk_Item *itemPtr, double deltaX, double deltaY)); - -/* - * The structures below defines the rectangle and oval item types - * by means of procedures that can be invoked by generic item code. - */ - -Tk_ItemType tkRectangleType = { - "rectangle", /* name */ - sizeof(RectOvalItem), /* itemSize */ - CreateRectOval, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureRectOval, /* configureProc */ - RectOvalCoords, /* coordProc */ - DeleteRectOval, /* deleteProc */ - DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ - RectToPoint, /* pointProc */ - RectToArea, /* areaProc */ - RectOvalToPostscript, /* postscriptProc */ - ScaleRectOval, /* scaleProc */ - TranslateRectOval, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* icursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -Tk_ItemType tkOvalType = { - "oval", /* name */ - sizeof(RectOvalItem), /* itemSize */ - CreateRectOval, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureRectOval, /* configureProc */ - RectOvalCoords, /* coordProc */ - DeleteRectOval, /* deleteProc */ - DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ - OvalToPoint, /* pointProc */ - OvalToArea, /* areaProc */ - RectOvalToPostscript, /* postscriptProc */ - ScaleRectOval, /* scaleProc */ - TranslateRectOval, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ - (Tk_ItemCursorProc *) NULL, /* cursorProc */ - (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ -}; - -/* - *-------------------------------------------------------------- - * - * CreateRectOval -- - * - * This procedure is invoked to create a new rectangle - * or oval item in a canvas. - * - * Results: - * A standard Tcl return value. If an error occurred in - * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, - * so it can be safely freed by the caller. - * - * Side effects: - * A new rectangle or oval item is created. - * - *-------------------------------------------------------------- - */ - -static int -CreateRectOval(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* For error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - - /* - * Carry out initialization that is needed in order to clean - * up after errors during the the remainder of this procedure. - */ - - rectOvalPtr->width = 1; - rectOvalPtr->outlineColor = NULL; - rectOvalPtr->fillColor = NULL; - rectOvalPtr->fillStipple = None; - rectOvalPtr->outlineGC = None; - rectOvalPtr->fillGC = None; - - /* - * Process the arguments to fill in the item record. - */ - - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &rectOvalPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; - } - - if (ConfigureRectOval(interp, canvas, itemPtr, argc-4, argv+4, 0) - != TCL_OK) { - DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * RectOvalCoords -- - * - * This procedure is invoked to process the "coords" widget - * command on rectangles and ovals. See the user documentation - * for details on what it does. - * - * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. - * - * Side effects: - * The coordinates for the given item may be changed. - * - *-------------------------------------------------------------- - */ - -static int -RectOvalCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; - - if (argc == 0) { - Tcl_PrintDouble(interp, rectOvalPtr->bbox[0], c0); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[1], c1); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[2], c2); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &rectOvalPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; - } - ComputeRectOvalBbox(canvas, rectOvalPtr); - } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 4, got %d", - argc); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ConfigureRectOval -- - * - * This procedure is invoked to configure various aspects - * of a rectangle or oval item, such as its border and - * background colors. - * - * Results: - * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. - * - * Side effects: - * Configuration information, such as colors and stipple - * patterns, may be set for itemPtr. - * - *-------------------------------------------------------------- - */ - -static int -ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing itemPtr. */ - Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - XGCValues gcValues; - GC newGC; - unsigned long mask; - Tk_Window tkwin; - - tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) rectOvalPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few of the options require additional processing, such as - * graphics contexts. - */ - - if (rectOvalPtr->width < 1) { - rectOvalPtr->width = 1; - } - if (rectOvalPtr->outlineColor == NULL) { - newGC = None; - } else { - gcValues.foreground = rectOvalPtr->outlineColor->pixel; - gcValues.cap_style = CapProjecting; - gcValues.line_width = rectOvalPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outlineGC); - } - rectOvalPtr->outlineGC = newGC; - - if (rectOvalPtr->fillColor == NULL) { - newGC = None; - } else { - gcValues.foreground = rectOvalPtr->fillColor->pixel; - if (rectOvalPtr->fillStipple != None) { - gcValues.stipple = rectOvalPtr->fillStipple; - gcValues.fill_style = FillStippled; - mask = GCForeground|GCStipple|GCFillStyle; - } else { - mask = GCForeground; - } - newGC = Tk_GetGC(tkwin, mask, &gcValues); - } - if (rectOvalPtr->fillGC != None) { - Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC); - } - rectOvalPtr->fillGC = newGC; - ComputeRectOvalBbox(canvas, rectOvalPtr); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * DeleteRectOval -- - * - * This procedure is called to clean up the data structure - * associated with a rectangle or oval item. - * - * Results: - * None. - * - * Side effects: - * Resources associated with itemPtr are released. - * - *-------------------------------------------------------------- - */ - -static void -DeleteRectOval(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - - if (rectOvalPtr->outlineColor != NULL) { - Tk_FreeColor(rectOvalPtr->outlineColor); - } - if (rectOvalPtr->fillColor != NULL) { - Tk_FreeColor(rectOvalPtr->fillColor); - } - if (rectOvalPtr->fillStipple != None) { - Tk_FreeBitmap(display, rectOvalPtr->fillStipple); - } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(display, rectOvalPtr->outlineGC); - } - if (rectOvalPtr->fillGC != None) { - Tk_FreeGC(display, rectOvalPtr->fillGC); - } -} - -/* - *-------------------------------------------------------------- - * - * ComputeRectOvalBbox -- - * - * This procedure is invoked to compute the bounding box of - * all the pixels that may be drawn as part of a rectangle - * or oval. - * - * Results: - * None. - * - * Side effects: - * The fields x1, y1, x2, and y2 are updated in the header - * for itemPtr. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -ComputeRectOvalBbox(canvas, rectOvalPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - RectOvalItem *rectOvalPtr; /* Item whose bbox is to be - * recomputed. */ -{ - int bloat, tmp; - double dtmp; - - /* - * Make sure that the first coordinates are the lowest ones. - */ - - if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) { - double tmp; - tmp = rectOvalPtr->bbox[3]; - rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1]; - rectOvalPtr->bbox[1] = tmp; - } - if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) { - double tmp; - tmp = rectOvalPtr->bbox[2]; - rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0]; - rectOvalPtr->bbox[0] = tmp; - } - - if (rectOvalPtr->outlineColor == NULL) { - bloat = 0; - } else { - bloat = (rectOvalPtr->width+1)/2; - } - - /* - * Special note: the rectangle is always drawn at least 1x1 in - * size, so round up the upper coordinates to be at least 1 unit - * greater than the lower ones. - */ - - tmp = (int) ((rectOvalPtr->bbox[0] >= 0) ? rectOvalPtr->bbox[0] + .5 - : rectOvalPtr->bbox[0] - .5); - rectOvalPtr->header.x1 = tmp - bloat; - tmp = (int) ((rectOvalPtr->bbox[1] >= 0) ? rectOvalPtr->bbox[1] + .5 - : rectOvalPtr->bbox[1] - .5); - rectOvalPtr->header.y1 = tmp - bloat; - dtmp = rectOvalPtr->bbox[2]; - if (dtmp < (rectOvalPtr->bbox[0] + 1)) { - dtmp = rectOvalPtr->bbox[0] + 1; - } - tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); - rectOvalPtr->header.x2 = tmp + bloat; - dtmp = rectOvalPtr->bbox[3]; - if (dtmp < (rectOvalPtr->bbox[1] + 1)) { - dtmp = rectOvalPtr->bbox[1] + 1; - } - tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); - rectOvalPtr->header.y2 = tmp + bloat; -} - -/* - *-------------------------------------------------------------- - * - * DisplayRectOval -- - * - * This procedure is invoked to draw a rectangle or oval - * item in a given drawable. - * - * Results: - * None. - * - * Side effects: - * ItemPtr is drawn in drawable using the transformation - * information in canvas. - * - *-------------------------------------------------------------- - */ - -static void -DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - short x1, y1, x2, y2; - - /* - * Compute the screen coordinates of the bounding box for the item. - * Make sure that the bbox is at least one pixel large, since some - * X servers will die if it isn't. - */ - - Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[0], rectOvalPtr->bbox[1], - &x1, &y1); - Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[2], rectOvalPtr->bbox[3], - &x2, &y2); - if (x2 <= x1) { - x2 = x1+1; - } - if (y2 <= y1) { - y2 = y1+1; - } - - /* - * Display filled part first (if wanted), then outline. If we're - * stippling, then modify the stipple offset in the GC. Be sure to - * reset the offset when done, since the GC is supposed to be - * read-only. - */ - - if (rectOvalPtr->fillGC != None) { - if (rectOvalPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, rectOvalPtr->fillGC); - } - if (rectOvalPtr->header.typePtr == &tkRectangleType) { - XFillRectangle(display, drawable, rectOvalPtr->fillGC, - x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1)); - } else { - XFillArc(display, drawable, rectOvalPtr->fillGC, - x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), - 0, 360*64); - } - if (rectOvalPtr->fillStipple != None) { - XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0); - } - } - if (rectOvalPtr->outlineGC != None) { - if (rectOvalPtr->header.typePtr == &tkRectangleType) { - XDrawRectangle(display, drawable, rectOvalPtr->outlineGC, - x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1)); - } else { - XDrawArc(display, drawable, rectOvalPtr->outlineGC, - x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); - } - } -} - -/* - *-------------------------------------------------------------- - * - * RectToPoint -- - * - * Computes the distance from a given point to a given - * rectangle, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the rectangle. If the - * point isn't inside the rectangle then the return value is the - * distance from the point to the rectangle. If itemPtr is filled, - * then anywhere in the interior is considered "inside"; if - * itemPtr isn't filled, then "inside" means only the area - * occupied by the outline. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -RectToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; - double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; - - /* - * Generate a new larger rectangle that includes the border - * width, if there is one. - */ - - x1 = rectPtr->bbox[0]; - y1 = rectPtr->bbox[1]; - x2 = rectPtr->bbox[2]; - y2 = rectPtr->bbox[3]; - if (rectPtr->outlineGC != None) { - inc = rectPtr->width/2.0; - x1 -= inc; - y1 -= inc; - x2 += inc; - y2 += inc; - } - - /* - * If the point is inside the rectangle, handle specially: - * distance is 0 if rectangle is filled, otherwise compute - * distance to nearest edge of rectangle and subtract width - * of edge. - */ - - if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) - && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { - if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) { - return 0.0; - } - xDiff = pointPtr[0] - x1; - tmp = x2 - pointPtr[0]; - if (tmp < xDiff) { - xDiff = tmp; - } - yDiff = pointPtr[1] - y1; - tmp = y2 - pointPtr[1]; - if (tmp < yDiff) { - yDiff = tmp; - } - if (yDiff < xDiff) { - xDiff = yDiff; - } - xDiff -= rectPtr->width; - if (xDiff < 0.0) { - return 0.0; - } - return xDiff; - } - - /* - * Point is outside rectangle. - */ - - if (pointPtr[0] < x1) { - xDiff = x1 - pointPtr[0]; - } else if (pointPtr[0] > x2) { - xDiff = pointPtr[0] - x2; - } else { - xDiff = 0; - } - - if (pointPtr[1] < y1) { - yDiff = y1 - pointPtr[1]; - } else if (pointPtr[1] > y2) { - yDiff = pointPtr[1] - y2; - } else { - yDiff = 0; - } - - return hypot(xDiff, yDiff); -} - -/* - *-------------------------------------------------------------- - * - * OvalToPoint -- - * - * Computes the distance from a given point to a given - * oval, in canvas units. - * - * Results: - * The return value is 0 if the point whose x and y coordinates - * are coordPtr[0] and coordPtr[1] is inside the oval. If the - * point isn't inside the oval then the return value is the - * distance from the point to the oval. If itemPtr is filled, - * then anywhere in the interior is considered "inside"; if - * itemPtr isn't filled, then "inside" means only the area - * occupied by the outline. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static double -OvalToPoint(canvas, itemPtr, pointPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against point. */ - double *pointPtr; /* Pointer to x and y coordinates. */ -{ - RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; - double width; - int filled; - - width = ovalPtr->width; - filled = ovalPtr->fillGC != None; - if (ovalPtr->outlineGC == None) { - width = 0.0; - filled = 1; - } - return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr); -} - -/* - *-------------------------------------------------------------- - * - * RectToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangle. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -RectToArea(canvas, itemPtr, areaPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against rectangle. */ - double *areaPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; - double halfWidth; - - halfWidth = rectPtr->width/2.0; - if (rectPtr->outlineGC == None) { - halfWidth = 0.0; - } - - if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth)) - || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth)) - || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth)) - || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { - return -1; - } - if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None) - && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) - && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) - && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) - && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) { - return -1; - } - if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth)) - && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth)) - && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth)) - && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) { - return 1; - } - return 0; -} - -/* - *-------------------------------------------------------------- - * - * OvalToArea -- - * - * This procedure is called to determine whether an item - * lies entirely inside, entirely outside, or overlapping - * a given rectangular area. - * - * Results: - * -1 is returned if the item is entirely outside the area - * given by rectPtr, 0 if it overlaps, and 1 if it is entirely - * inside the given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -OvalToArea(canvas, itemPtr, areaPtr) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item to check against oval. */ - double *areaPtr; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) describing rectangular - * area. */ -{ - RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; - double oval[4], halfWidth; - int result; - - /* - * Expand the oval to include the width of the outline, if any. - */ - - halfWidth = ovalPtr->width/2.0; - if (ovalPtr->outlineGC == None) { - halfWidth = 0.0; - } - oval[0] = ovalPtr->bbox[0] - halfWidth; - oval[1] = ovalPtr->bbox[1] - halfWidth; - oval[2] = ovalPtr->bbox[2] + halfWidth; - oval[3] = ovalPtr->bbox[3] + halfWidth; - - result = TkOvalToArea(oval, areaPtr); - - /* - * If the rectangle appears to overlap the oval and the oval - * isn't filled, do one more check to see if perhaps all four - * of the rectangle's corners are totally inside the oval's - * unfilled center, in which case we should return "outside". - */ - - if ((result == 0) && (ovalPtr->outlineGC != None) - && (ovalPtr->fillGC == None)) { - double centerX, centerY, width, height; - double xDelta1, yDelta1, xDelta2, yDelta2; - - centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; - centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; - width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; - height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; - xDelta1 = (areaPtr[0] - centerX)/width; - xDelta1 *= xDelta1; - yDelta1 = (areaPtr[1] - centerY)/height; - yDelta1 *= yDelta1; - xDelta2 = (areaPtr[2] - centerX)/width; - xDelta2 *= xDelta2; - yDelta2 = (areaPtr[3] - centerY)/height; - yDelta2 *= yDelta2; - if (((xDelta1 + yDelta1) < 1.0) - && ((xDelta1 + yDelta2) < 1.0) - && ((xDelta2 + yDelta1) < 1.0) - && ((xDelta2 + yDelta2) < 1.0)) { - return -1; - } - } - return result; -} - -/* - *-------------------------------------------------------------- - * - * ScaleRectOval -- - * - * This procedure is invoked to rescale a rectangle or oval - * item. - * - * Results: - * None. - * - * Side effects: - * The rectangle or oval referred to by itemPtr is rescaled - * so that the following transformation is applied to all - * point coordinates: - * x' = originX + scaleX*(x-originX) - * y' = originY + scaleY*(y-originY) - * - *-------------------------------------------------------------- - */ - -static void -ScaleRectOval(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - - rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX); - rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY); - rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX); - rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY); - ComputeRectOvalBbox(canvas, rectOvalPtr); -} - -/* - *-------------------------------------------------------------- - * - * TranslateRectOval -- - * - * This procedure is called to move a rectangle or oval by a - * given amount. - * - * Results: - * None. - * - * Side effects: - * The position of the rectangle or oval is offset by - * (xDelta, yDelta), and the bounding box is updated in the - * generic part of the item structure. - * - *-------------------------------------------------------------- - */ - -static void -TranslateRectOval(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ -{ - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - - rectOvalPtr->bbox[0] += deltaX; - rectOvalPtr->bbox[1] += deltaY; - rectOvalPtr->bbox[2] += deltaX; - rectOvalPtr->bbox[3] += deltaY; - ComputeRectOvalBbox(canvas, rectOvalPtr); -} - -/* - *-------------------------------------------------------------- - * - * RectOvalToPostscript -- - * - * This procedure is called to generate Postscript for - * rectangle and oval items. - * - * Results: - * The return value is a standard Tcl result. If an error - * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used to be there. - * If no error occurs, then Postscript for the rectangle is - * appended to the result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -RectOvalToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ -{ - char pathCmd[500], string[100]; - RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - double y1, y2; - - y1 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[1]); - y2 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[3]); - - /* - * Generate a string that creates a path for the rectangle or oval. - * This is the only part of the procedure's code that is type- - * specific. - */ - - - if (rectOvalPtr->header.typePtr == &tkRectangleType) { - sprintf(pathCmd, "%.15g %.15g moveto %.15g 0 rlineto 0 %.15g rlineto %.15g 0 rlineto closepath\n", - rectOvalPtr->bbox[0], y1, - rectOvalPtr->bbox[2]-rectOvalPtr->bbox[0], y2-y1, - rectOvalPtr->bbox[0]-rectOvalPtr->bbox[2]); - } else { - sprintf(pathCmd, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", - (rectOvalPtr->bbox[0] + rectOvalPtr->bbox[2])/2, (y1 + y2)/2, - (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2); - } - - /* - * First draw the filled area of the rectangle. - */ - - if (rectOvalPtr->fillColor != NULL) { - Tcl_AppendResult(interp, pathCmd, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->fillColor) - != TCL_OK) { - return TCL_ERROR; - } - if (rectOvalPtr->fillStipple != None) { - Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, rectOvalPtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - if (rectOvalPtr->outlineColor != NULL) { - Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - } - } else { - Tcl_AppendResult(interp, "fill\n", (char *) NULL); - } - } - - /* - * Now draw the outline, if there is one. - */ - - if (rectOvalPtr->outlineColor != NULL) { - Tcl_AppendResult(interp, pathCmd, (char *) NULL); - sprintf(string, "%d setlinewidth", rectOvalPtr->width); - Tcl_AppendResult(interp, string, - " 0 setlinejoin 2 setlinecap\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->outlineColor) - != TCL_OK) { - return TCL_ERROR; - } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - return TCL_OK; -} diff --git a/generic/tkScale.c b/generic/tkScale.c deleted file mode 100644 index 8cdfc3c..0000000 --- a/generic/tkScale.c +++ /dev/null @@ -1,1143 +0,0 @@ -/* - * tkScale.c -- - * - * This module implements a scale widgets for the Tk toolkit. - * A scale displays a slider that can be adjusted to change a - * value; it also displays numeric labels and a textual label, - * if desired. - * - * The modifications to use floating-point values are based on - * an implementation by Paul Mackerras. The -variable option - * is due to Henning Schulzrinne. All of these are used with - * permission. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkScale.c,v 1.2 1998/09/14 18:23:16 stanton Exp $ - */ - -#include "tkPort.h" -#include "default.h" -#include "tkInt.h" -#include "tclMath.h" -#include "tkScale.h" - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCALE_ACTIVE_BG_COLOR, Tk_Offset(TkScale, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCALE_ACTIVE_BG_MONO, Tk_Offset(TkScale, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCALE_BG_COLOR, Tk_Offset(TkScale, bgBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCALE_BG_MONO, Tk_Offset(TkScale, bgBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_DOUBLE, "-bigincrement", "bigIncrement", "BigIncrement", - DEF_SCALE_BIG_INCREMENT, Tk_Offset(TkScale, bigIncrement), 0}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_SCALE_BORDER_WIDTH, Tk_Offset(TkScale, borderWidth), 0}, - {TK_CONFIG_STRING, "-command", "command", "Command", - DEF_SCALE_COMMAND, Tk_Offset(TkScale, command), TK_CONFIG_NULL_OK}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_SCALE_CURSOR, Tk_Offset(TkScale, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-digits", "digits", "Digits", - DEF_SCALE_DIGITS, Tk_Offset(TkScale, digits), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_SCALE_FONT, Tk_Offset(TkScale, tkfont), - 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_SCALE_FG_COLOR, Tk_Offset(TkScale, textColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_SCALE_FG_MONO, Tk_Offset(TkScale, textColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_DOUBLE, "-from", "from", "From", - DEF_SCALE_FROM, Tk_Offset(TkScale, fromValue), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_SCALE_HIGHLIGHT_BG, - Tk_Offset(TkScale, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_SCALE_HIGHLIGHT, Tk_Offset(TkScale, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_SCALE_HIGHLIGHT_WIDTH, Tk_Offset(TkScale, highlightWidth), 0}, - {TK_CONFIG_STRING, "-label", "label", "Label", - DEF_SCALE_LABEL, Tk_Offset(TkScale, label), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-length", "length", "Length", - DEF_SCALE_LENGTH, Tk_Offset(TkScale, length), 0}, - {TK_CONFIG_UID, "-orient", "orient", "Orient", - DEF_SCALE_ORIENT, Tk_Offset(TkScale, orientUid), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_SCALE_RELIEF, Tk_Offset(TkScale, relief), 0}, - {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", - DEF_SCALE_REPEAT_DELAY, Tk_Offset(TkScale, repeatDelay), 0}, - {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", - DEF_SCALE_REPEAT_INTERVAL, Tk_Offset(TkScale, repeatInterval), 0}, - {TK_CONFIG_DOUBLE, "-resolution", "resolution", "Resolution", - DEF_SCALE_RESOLUTION, Tk_Offset(TkScale, resolution), 0}, - {TK_CONFIG_BOOLEAN, "-showvalue", "showValue", "ShowValue", - DEF_SCALE_SHOW_VALUE, Tk_Offset(TkScale, showValue), 0}, - {TK_CONFIG_PIXELS, "-sliderlength", "sliderLength", "SliderLength", - DEF_SCALE_SLIDER_LENGTH, Tk_Offset(TkScale, sliderLength), 0}, - {TK_CONFIG_RELIEF, "-sliderrelief", "sliderRelief", "SliderRelief", - DEF_SCALE_SLIDER_RELIEF, Tk_Offset(TkScale, sliderRelief), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_SCALE_STATE, Tk_Offset(TkScale, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_SCALE_TAKE_FOCUS, Tk_Offset(TkScale, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_DOUBLE, "-tickinterval", "tickInterval", "TickInterval", - DEF_SCALE_TICK_INTERVAL, Tk_Offset(TkScale, tickInterval), 0}, - {TK_CONFIG_DOUBLE, "-to", "to", "To", - DEF_SCALE_TO, Tk_Offset(TkScale, toValue), 0}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCALE_TROUGH_COLOR, Tk_Offset(TkScale, troughColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCALE_TROUGH_MONO, Tk_Offset(TkScale, troughColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_SCALE_VARIABLE, Tk_Offset(TkScale, varName), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_SCALE_WIDTH, Tk_Offset(TkScale, width), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void ComputeFormat _ANSI_ARGS_((TkScale *scalePtr)); -static void ComputeScaleGeometry _ANSI_ARGS_((TkScale *scalePtr)); -static int ConfigureScale _ANSI_ARGS_((Tcl_Interp *interp, - TkScale *scalePtr, int argc, char **argv, - int flags)); -static void DestroyScale _ANSI_ARGS_((char *memPtr)); -static void ScaleCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void ScaleEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static char * ScaleVarProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *name1, char *name2, - int flags)); -static int ScaleWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void ScaleWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); - -/* - * The structure below defines scale class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs scaleClass = { - NULL, /* createProc. */ - ScaleWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_ScaleCmd -- - * - * This procedure is invoked to process the "scale" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_ScaleCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - register TkScale *scalePtr; - Tk_Window new; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - scalePtr = TkpCreateScale(new); - - /* - * Initialize fields that won't be initialized by ConfigureScale, - * or which ConfigureScale expects to have reasonable values - * (e.g. resource pointers). - */ - - scalePtr->tkwin = new; - scalePtr->display = Tk_Display(new); - scalePtr->interp = interp; - scalePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(scalePtr->tkwin), ScaleWidgetCmd, - (ClientData) scalePtr, ScaleCmdDeletedProc); - scalePtr->orientUid = NULL; - scalePtr->vertical = 0; - scalePtr->width = 0; - scalePtr->length = 0; - scalePtr->value = 0; - scalePtr->varName = NULL; - scalePtr->fromValue = 0; - scalePtr->toValue = 0; - scalePtr->tickInterval = 0; - scalePtr->resolution = 1; - scalePtr->bigIncrement = 0.0; - scalePtr->command = NULL; - scalePtr->repeatDelay = 0; - scalePtr->repeatInterval = 0; - scalePtr->label = NULL; - scalePtr->labelLength = 0; - scalePtr->state = tkNormalUid; - scalePtr->borderWidth = 0; - scalePtr->bgBorder = NULL; - scalePtr->activeBorder = NULL; - scalePtr->sliderRelief = TK_RELIEF_RAISED; - scalePtr->troughColorPtr = NULL; - scalePtr->troughGC = None; - scalePtr->copyGC = None; - scalePtr->tkfont = NULL; - scalePtr->textColorPtr = NULL; - scalePtr->textGC = None; - scalePtr->relief = TK_RELIEF_FLAT; - scalePtr->highlightWidth = 0; - scalePtr->highlightBgColorPtr = NULL; - scalePtr->highlightColorPtr = NULL; - scalePtr->inset = 0; - scalePtr->sliderLength = 0; - scalePtr->showValue = 0; - scalePtr->horizLabelY = 0; - scalePtr->horizValueY = 0; - scalePtr->horizTroughY = 0; - scalePtr->horizTickY = 0; - scalePtr->vertTickRightX = 0; - scalePtr->vertValueRightX = 0; - scalePtr->vertTroughX = 0; - scalePtr->vertLabelX = 0; - scalePtr->cursor = None; - scalePtr->takeFocus = NULL; - scalePtr->flags = NEVER_SET; - - Tk_SetClass(scalePtr->tkwin, "Scale"); - TkSetClassProcs(scalePtr->tkwin, &scaleClass, (ClientData) scalePtr); - Tk_CreateEventHandler(scalePtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - ScaleEventProc, (ClientData) scalePtr); - if (ConfigureScale(interp, scalePtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - - interp->result = Tk_PathName(scalePtr->tkwin); - return TCL_OK; - - error: - Tk_DestroyWindow(scalePtr->tkwin); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * ScaleWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ScaleWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about scale - * widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkScale *scalePtr = (TkScale *) clientData; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) scalePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, argv[2], 0); - } else { - result = ConfigureScale(interp, scalePtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0) - && (length >= 3)) { - int x, y ; - double value; - - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " coords ?value?\"", (char *) NULL); - goto error; - } - if (argc == 3) { - if (Tcl_GetDouble(interp, argv[2], &value) != TCL_OK) { - goto error; - } - } else { - value = scalePtr->value; - } - if (scalePtr->vertical) { - x = scalePtr->vertTroughX + scalePtr->width/2 - + scalePtr->borderWidth; - y = TkpValueToPixel(scalePtr, value); - } else { - x = TkpValueToPixel(scalePtr, value); - y = scalePtr->horizTroughY + scalePtr->width/2 - + scalePtr->borderWidth; - } - sprintf(interp->result, "%d %d", x, y); - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - double value; - int x, y; - - if ((argc != 2) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get ?x y?\"", (char *) NULL); - goto error; - } - if (argc == 2) { - value = scalePtr->value; - } else { - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - value = TkpPixelToValue(scalePtr, x, y); - } - sprintf(interp->result, scalePtr->format, value); - } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { - int x, y, thing; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " identify x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - thing = TkpScaleElement(scalePtr, x,y); - switch (thing) { - case TROUGH1: interp->result = "trough1"; break; - case SLIDER: interp->result = "slider"; break; - case TROUGH2: interp->result = "trough2"; break; - } - } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { - double value; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " set value\"", (char *) NULL); - goto error; - } - if (Tcl_GetDouble(interp, argv[2], &value) != TCL_OK) { - goto error; - } - if (scalePtr->state != tkDisabledUid) { - TkpSetScaleValue(scalePtr, value, 1, 1); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget, configure, coords, get, identify, or set", - (char *) NULL); - goto error; - } - Tcl_Release((ClientData) scalePtr); - return result; - - error: - Tcl_Release((ClientData) scalePtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyScale -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a button at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the scale is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyScale(memPtr) - char *memPtr; /* Info about scale widget. */ -{ - register TkScale *scalePtr = (TkScale *) memPtr; - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - if (scalePtr->varName != NULL) { - Tcl_UntraceVar(scalePtr->interp, scalePtr->varName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ScaleVarProc, (ClientData) scalePtr); - } - if (scalePtr->troughGC != None) { - Tk_FreeGC(scalePtr->display, scalePtr->troughGC); - } - if (scalePtr->copyGC != None) { - Tk_FreeGC(scalePtr->display, scalePtr->copyGC); - } - if (scalePtr->textGC != None) { - Tk_FreeGC(scalePtr->display, scalePtr->textGC); - } - Tk_FreeOptions(configSpecs, (char *) scalePtr, scalePtr->display, 0); - TkpDestroyScale(scalePtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureScale -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a scale widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for scalePtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureScale(interp, scalePtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkScale *scalePtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - size_t length; - - /* - * Eliminate any existing trace on a variable monitored by the scale. - */ - - if (scalePtr->varName != NULL) { - Tcl_UntraceVar(interp, scalePtr->varName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ScaleVarProc, (ClientData) scalePtr); - } - - if (Tk_ConfigureWidget(interp, scalePtr->tkwin, configSpecs, - argc, argv, (char *) scalePtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * If the scale is tied to the value of a variable, then set up - * a trace on the variable's value and set the scale's value from - * the value of the variable, if it exists. - */ - - if (scalePtr->varName != NULL) { - char *stringValue, *end; - double value; - - stringValue = Tcl_GetVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY); - if (stringValue != NULL) { - value = strtod(stringValue, &end); - if ((end != stringValue) && (*end == 0)) { - scalePtr->value = TkRoundToResolution(scalePtr, value); - } - } - Tcl_TraceVar(interp, scalePtr->varName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ScaleVarProc, (ClientData) scalePtr); - } - - /* - * Several options need special processing, such as parsing the - * orientation and creating GCs. - */ - - length = strlen(scalePtr->orientUid); - if (strncmp(scalePtr->orientUid, "vertical", length) == 0) { - scalePtr->vertical = 1; - } else if (strncmp(scalePtr->orientUid, "horizontal", length) == 0) { - scalePtr->vertical = 0; - } else { - Tcl_AppendResult(interp, "bad orientation \"", scalePtr->orientUid, - "\": must be vertical or horizontal", (char *) NULL); - return TCL_ERROR; - } - - scalePtr->fromValue = TkRoundToResolution(scalePtr, scalePtr->fromValue); - scalePtr->toValue = TkRoundToResolution(scalePtr, scalePtr->toValue); - scalePtr->tickInterval = TkRoundToResolution(scalePtr, - scalePtr->tickInterval); - - /* - * Make sure that the tick interval has the right sign so that - * addition moves from fromValue to toValue. - */ - - if ((scalePtr->tickInterval < 0) - ^ ((scalePtr->toValue - scalePtr->fromValue) < 0)) { - scalePtr->tickInterval = -scalePtr->tickInterval; - } - - /* - * Set the scale value to itself; all this does is to make sure - * that the scale's value is within the new acceptable range for - * the scale and reflect the value in the associated variable, - * if any. - */ - - ComputeFormat(scalePtr); - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 1); - - if (scalePtr->label != NULL) { - scalePtr->labelLength = strlen(scalePtr->label); - } else { - scalePtr->labelLength = 0; - } - - if ((scalePtr->state != tkNormalUid) - && (scalePtr->state != tkDisabledUid) - && (scalePtr->state != tkActiveUid)) { - Tcl_AppendResult(interp, "bad state value \"", scalePtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - scalePtr->state = tkNormalUid; - return TCL_ERROR; - } - - Tk_SetBackgroundFromBorder(scalePtr->tkwin, scalePtr->bgBorder); - - if (scalePtr->highlightWidth < 0) { - scalePtr->highlightWidth = 0; - } - scalePtr->inset = scalePtr->highlightWidth + scalePtr->borderWidth; - - ScaleWorldChanged((ClientData) scalePtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ScaleWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Scale will be relayed out and redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -ScaleWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - XGCValues gcValues; - GC gc; - TkScale *scalePtr; - - scalePtr = (TkScale *) instanceData; - - gcValues.foreground = scalePtr->troughColorPtr->pixel; - gc = Tk_GetGC(scalePtr->tkwin, GCForeground, &gcValues); - if (scalePtr->troughGC != None) { - Tk_FreeGC(scalePtr->display, scalePtr->troughGC); - } - scalePtr->troughGC = gc; - - gcValues.font = Tk_FontId(scalePtr->tkfont); - gcValues.foreground = scalePtr->textColorPtr->pixel; - gc = Tk_GetGC(scalePtr->tkwin, GCForeground | GCFont, &gcValues); - if (scalePtr->textGC != None) { - Tk_FreeGC(scalePtr->display, scalePtr->textGC); - } - scalePtr->textGC = gc; - - if (scalePtr->copyGC == None) { - gcValues.graphics_exposures = False; - scalePtr->copyGC = Tk_GetGC(scalePtr->tkwin, GCGraphicsExposures, - &gcValues); - } - scalePtr->inset = scalePtr->highlightWidth + scalePtr->borderWidth; - - /* - * Recompute display-related information, and let the geometry - * manager know how much space is needed now. - */ - - ComputeScaleGeometry(scalePtr); - - TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); -} - -/* - *---------------------------------------------------------------------- - * - * ComputeFormat -- - * - * This procedure is invoked to recompute the "format" field - * of a scale's widget record, which determines how the value - * of the scale is converted to a string. - * - * Results: - * None. - * - * Side effects: - * The format field of scalePtr is modified. - * - *---------------------------------------------------------------------- - */ - -static void -ComputeFormat(scalePtr) - TkScale *scalePtr; /* Information about scale widget. */ -{ - double maxValue, x; - int mostSigDigit, numDigits, leastSigDigit, afterDecimal; - int eDigits, fDigits; - - /* - * Compute the displacement from the decimal of the most significant - * digit required for any number in the scale's range. - */ - - maxValue = fabs(scalePtr->fromValue); - x = fabs(scalePtr->toValue); - if (x > maxValue) { - maxValue = x; - } - if (maxValue == 0) { - maxValue = 1; - } - mostSigDigit = (int) floor(log10(maxValue)); - - /* - * If the number of significant digits wasn't specified explicitly, - * compute it. It's the difference between the most significant - * digit needed to represent any number on the scale and the - * most significant digit of the smallest difference between - * numbers on the scale. In other words, display enough digits so - * that at least one digit will be different between any two adjacent - * positions of the scale. - */ - - numDigits = scalePtr->digits; - if (numDigits <= 0) { - if (scalePtr->resolution > 0) { - /* - * A resolution was specified for the scale, so just use it. - */ - - leastSigDigit = (int) floor(log10(scalePtr->resolution)); - } else { - /* - * No resolution was specified, so compute the difference - * in value between adjacent pixels and use it for the least - * significant digit. - */ - - x = fabs(scalePtr->fromValue - scalePtr->toValue); - if (scalePtr->length > 0) { - x /= scalePtr->length; - } - if (x > 0){ - leastSigDigit = (int) floor(log10(x)); - } else { - leastSigDigit = 0; - } - } - numDigits = mostSigDigit - leastSigDigit + 1; - if (numDigits < 1) { - numDigits = 1; - } - } - - /* - * Compute the number of characters required using "e" format and - * "f" format, and then choose whichever one takes fewer characters. - */ - - eDigits = numDigits + 4; - if (numDigits > 1) { - eDigits++; /* Decimal point. */ - } - afterDecimal = numDigits - mostSigDigit - 1; - if (afterDecimal < 0) { - afterDecimal = 0; - } - fDigits = (mostSigDigit >= 0) ? mostSigDigit + afterDecimal : afterDecimal; - if (afterDecimal > 0) { - fDigits++; /* Decimal point. */ - } - if (mostSigDigit < 0) { - fDigits++; /* Zero to left of decimal point. */ - } - if (fDigits <= eDigits) { - sprintf(scalePtr->format, "%%.%df", afterDecimal); - } else { - sprintf(scalePtr->format, "%%.%de", numDigits-1); - } -} - -/* - *---------------------------------------------------------------------- - * - * ComputeScaleGeometry -- - * - * This procedure is called to compute various geometrical - * information for a scale, such as where various things get - * displayed. It's called when the window is reconfigured. - * - * Results: - * None. - * - * Side effects: - * Display-related numbers get changed in *scalePtr. The - * geometry manager gets told about the window's preferred size. - * - *---------------------------------------------------------------------- - */ - -static void -ComputeScaleGeometry(scalePtr) - register TkScale *scalePtr; /* Information about widget. */ -{ - char valueString[PRINT_CHARS]; - int tmp, valuePixels, x, y, extraSpace; - Tk_FontMetrics fm; - - /* - * Horizontal scales are simpler than vertical ones because - * all sizes are the same (the height of a line of text); - * handle them first and then quit. - */ - - Tk_GetFontMetrics(scalePtr->tkfont, &fm); - if (!scalePtr->vertical) { - y = scalePtr->inset; - extraSpace = 0; - if (scalePtr->labelLength != 0) { - scalePtr->horizLabelY = y + SPACING; - y += fm.linespace + SPACING; - extraSpace = SPACING; - } - if (scalePtr->showValue) { - scalePtr->horizValueY = y + SPACING; - y += fm.linespace + SPACING; - extraSpace = SPACING; - } else { - scalePtr->horizValueY = y; - } - y += extraSpace; - scalePtr->horizTroughY = y; - y += scalePtr->width + 2*scalePtr->borderWidth; - if (scalePtr->tickInterval != 0) { - scalePtr->horizTickY = y + SPACING; - y += fm.linespace + 2*SPACING; - } - Tk_GeometryRequest(scalePtr->tkwin, - scalePtr->length + 2*scalePtr->inset, y + scalePtr->inset); - Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->inset); - return; - } - - /* - * Vertical scale: compute the amount of space needed to display - * the scales value by formatting strings for the two end points; - * use whichever length is longer. - */ - - sprintf(valueString, scalePtr->format, scalePtr->fromValue); - valuePixels = Tk_TextWidth(scalePtr->tkfont, valueString, -1); - - sprintf(valueString, scalePtr->format, scalePtr->toValue); - tmp = Tk_TextWidth(scalePtr->tkfont, valueString, -1); - if (valuePixels < tmp) { - valuePixels = tmp; - } - - /* - * Assign x-locations to the elements of the scale, working from - * left to right. - */ - - x = scalePtr->inset; - if ((scalePtr->tickInterval != 0) && (scalePtr->showValue)) { - scalePtr->vertTickRightX = x + SPACING + valuePixels; - scalePtr->vertValueRightX = scalePtr->vertTickRightX + valuePixels - + fm.ascent/2; - x = scalePtr->vertValueRightX + SPACING; - } else if (scalePtr->tickInterval != 0) { - scalePtr->vertTickRightX = x + SPACING + valuePixels; - scalePtr->vertValueRightX = scalePtr->vertTickRightX; - x = scalePtr->vertTickRightX + SPACING; - } else if (scalePtr->showValue) { - scalePtr->vertTickRightX = x; - scalePtr->vertValueRightX = x + SPACING + valuePixels; - x = scalePtr->vertValueRightX + SPACING; - } else { - scalePtr->vertTickRightX = x; - scalePtr->vertValueRightX = x; - } - scalePtr->vertTroughX = x; - x += 2*scalePtr->borderWidth + scalePtr->width; - if (scalePtr->labelLength == 0) { - scalePtr->vertLabelX = 0; - } else { - scalePtr->vertLabelX = x + fm.ascent/2; - x = scalePtr->vertLabelX + fm.ascent/2 - + Tk_TextWidth(scalePtr->tkfont, scalePtr->label, - scalePtr->labelLength); - } - Tk_GeometryRequest(scalePtr->tkwin, x + scalePtr->inset, - scalePtr->length + 2*scalePtr->inset); - Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->inset); -} - -/* - *-------------------------------------------------------------- - * - * ScaleEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on scales. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -ScaleEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkScale *scalePtr = (TkScale *) clientData; - - if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { - TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); - } else if (eventPtr->type == DestroyNotify) { - if (scalePtr->tkwin != NULL) { - scalePtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(scalePtr->interp, scalePtr->widgetCmd); - } - if (scalePtr->flags & REDRAW_ALL) { - Tcl_CancelIdleCall(TkpDisplayScale, (ClientData) scalePtr); - } - Tcl_EventuallyFree((ClientData) scalePtr, DestroyScale); - } else if (eventPtr->type == ConfigureNotify) { - ComputeScaleGeometry(scalePtr); - TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - scalePtr->flags |= GOT_FOCUS; - if (scalePtr->highlightWidth > 0) { - TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - scalePtr->flags &= ~GOT_FOCUS; - if (scalePtr->highlightWidth > 0) { - TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ScaleCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -ScaleCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkScale *scalePtr = (TkScale *) clientData; - Tk_Window tkwin = scalePtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - scalePtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * TkEventuallyRedrawScale -- - * - * Arrange for part or all of a scale widget to redrawn at - * the next convenient time in the future. - * - * Results: - * None. - * - * Side effects: - * If "what" is REDRAW_SLIDER then just the slider and the - * value readout will be redrawn; if "what" is REDRAW_ALL - * then the entire widget will be redrawn. - * - *-------------------------------------------------------------- - */ - -void -TkEventuallyRedrawScale(scalePtr, what) - register TkScale *scalePtr; /* Information about widget. */ - int what; /* What to redraw: REDRAW_SLIDER - * or REDRAW_ALL. */ -{ - if ((what == 0) || (scalePtr->tkwin == NULL) - || !Tk_IsMapped(scalePtr->tkwin)) { - return; - } - if ((scalePtr->flags & REDRAW_ALL) == 0) { - Tcl_DoWhenIdle(TkpDisplayScale, (ClientData) scalePtr); - } - scalePtr->flags |= what; -} - -/* - *-------------------------------------------------------------- - * - * TkRoundToResolution -- - * - * Round a given floating-point value to the nearest multiple - * of the scale's resolution. - * - * Results: - * The return value is the rounded result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -double -TkRoundToResolution(scalePtr, value) - TkScale *scalePtr; /* Information about scale widget. */ - double value; /* Value to round. */ -{ - double rem, new; - - if (scalePtr->resolution <= 0) { - return value; - } - new = scalePtr->resolution * floor(value/scalePtr->resolution); - rem = value - new; - if (rem < 0) { - if (rem <= -scalePtr->resolution/2) { - new -= scalePtr->resolution; - } - } else { - if (rem >= scalePtr->resolution/2) { - new += scalePtr->resolution; - } - } - return new; -} - -/* - *---------------------------------------------------------------------- - * - * ScaleVarProc -- - * - * This procedure is invoked by Tcl whenever someone modifies a - * variable associated with a scale widget. - * - * Results: - * NULL is always returned. - * - * Side effects: - * The value displayed in the scale will change to match the - * variable's new value. If the variable has a bogus value then - * it is reset to the value of the scale. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -ScaleVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Information about button. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -{ - register TkScale *scalePtr = (TkScale *) clientData; - char *stringValue, *end, *result; - double value; - - /* - * If the variable is unset, then immediately recreate it unless - * the whole interpreter is going away. - */ - - if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, scalePtr->varName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ScaleVarProc, clientData); - scalePtr->flags |= NEVER_SET; - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); - } - return (char *) NULL; - } - - /* - * If we came here because we updated the variable (in TkpSetScaleValue), - * then ignore the trace. Otherwise update the scale with the value - * of the variable. - */ - - if (scalePtr->flags & SETTING_VAR) { - return (char *) NULL; - } - result = NULL; - stringValue = Tcl_GetVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY); - if (stringValue != NULL) { - value = strtod(stringValue, &end); - if ((end == stringValue) || (*end != 0)) { - result = "can't assign non-numeric value to scale variable"; - } else { - scalePtr->value = TkRoundToResolution(scalePtr, value); - } - - /* - * This code is a bit tricky because it sets the scale's value before - * calling TkpSetScaleValue. This way, TkpSetScaleValue won't bother - * to set the variable again or to invoke the -command. However, it - * also won't redisplay the scale, so we have to ask for that - * explicitly. - */ - - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); - TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); - } - - return result; -} diff --git a/generic/tkScale.h b/generic/tkScale.h deleted file mode 100644 index 7200fb2..0000000 --- a/generic/tkScale.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * tkScale.h -- - * - * Declarations of types and functions used to implement - * the scale widget. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkScale.h,v 1.4 1998/09/14 18:23:17 stanton Exp $ - */ - -#ifndef _TKSCALE -#define _TKSCALE - -#ifndef _TK -#include "tk.h" -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * A data structure of the following type is kept for each scale - * widget managed by this file: - */ - -typedef struct TkScale { - Tk_Window tkwin; /* Window that embodies the scale. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with scale. */ - Tcl_Command widgetCmd; /* Token for scale's widget command. */ - Tk_Uid orientUid; /* Orientation for window ("vertical" or - * "horizontal"). */ - int vertical; /* Non-zero means vertical orientation, - * zero means horizontal. */ - int width; /* Desired narrow dimension of scale, - * in pixels. */ - int length; /* Desired long dimension of scale, - * in pixels. */ - double value; /* Current value of scale. */ - char *varName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, scale's value tracks - * the contents of this variable and - * vice versa. */ - double fromValue; /* Value corresponding to left or top of - * scale. */ - double toValue; /* Value corresponding to right or bottom - * of scale. */ - double tickInterval; /* Distance between tick marks; 0 means - * don't display any tick marks. */ - double resolution; /* If > 0, all values are rounded to an - * even multiple of this value. */ - int digits; /* Number of significant digits to print - * in values. 0 means we get to choose the - * number based on resolution and/or the - * range of the scale. */ - char format[10]; /* Sprintf conversion specifier computed from - * digits and other information. */ - double bigIncrement; /* Amount to use for large increments to - * scale value. (0 means we pick a value). */ - char *command; /* Command prefix to use when invoking Tcl - * commands because the scale value changed. - * NULL means don't invoke commands. - * Malloc'ed. */ - int repeatDelay; /* How long to wait before auto-repeating - * on scrolling actions (in ms). */ - int repeatInterval; /* Interval between autorepeats (in ms). */ - char *label; /* Label to display above or to right of - * scale; NULL means don't display a - * label. Malloc'ed. */ - int labelLength; /* Number of non-NULL chars. in label. */ - Tk_Uid state; /* Normal or disabled. Value cannot be - * changed when scale is disabled. */ - - /* - * Information used when displaying widget: - */ - - int borderWidth; /* Width of 3-D border around window. */ - Tk_3DBorder bgBorder; /* Used for drawing slider and other - * background areas. */ - Tk_3DBorder activeBorder; /* For drawing the slider when active. */ - int sliderRelief; /* Is slider to be drawn raised, sunken, etc. */ - XColor *troughColorPtr; /* Color for drawing trough. */ - GC troughGC; /* For drawing trough. */ - GC copyGC; /* Used for copying from pixmap onto screen. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *textColorPtr; /* Color for drawing text. */ - GC textGC; /* GC for drawing text in normal mode. */ - int relief; /* Indicates whether window as a whole is - * raised, sunken, or flat. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - int sliderLength; /* Length of slider, measured in pixels along - * long dimension of scale. */ - int showValue; /* Non-zero means to display the scale value - * below or to the left of the slider; zero - * means don't display the value. */ - - /* - * Layout information for horizontal scales, assuming that window - * gets the size it requested: - */ - - int horizLabelY; /* Y-coord at which to draw label. */ - int horizValueY; /* Y-coord at which to draw value text. */ - int horizTroughY; /* Y-coord of top of slider trough. */ - int horizTickY; /* Y-coord at which to draw tick text. */ - /* - * Layout information for vertical scales, assuming that window - * gets the size it requested: - */ - - int vertTickRightX; /* X-location of right side of tick-marks. */ - int vertValueRightX; /* X-location of right side of value string. */ - int vertTroughX; /* X-location of scale's slider trough. */ - int vertLabelX; /* X-location of origin of label. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int flags; /* Various flags; see below for - * definitions. */ -} TkScale; - -/* - * Flag bits for scales: - * - * REDRAW_SLIDER - 1 means slider (and numerical readout) need - * to be redrawn. - * REDRAW_OTHER - 1 means other stuff besides slider and value - * need to be redrawn. - * REDRAW_ALL - 1 means the entire widget needs to be redrawn. - * ACTIVE - 1 means the widget is active (the mouse is - * in its window). - * INVOKE_COMMAND - 1 means the scale's command needs to be - * invoked during the next redisplay (the - * value of the scale has changed since the - * last time the command was invoked). - * SETTING_VAR - 1 means that the associated variable is - * being set by us, so there's no need for - * ScaleVarProc to do anything. - * NEVER_SET - 1 means that the scale's value has never - * been set before (so must invoke -command and - * set associated variable even if the value - * doesn't appear to have changed). - * GOT_FOCUS - 1 means that the focus is currently in - * this widget. - */ - -#define REDRAW_SLIDER 1 -#define REDRAW_OTHER 2 -#define REDRAW_ALL 3 -#define ACTIVE 4 -#define INVOKE_COMMAND 0x10 -#define SETTING_VAR 0x20 -#define NEVER_SET 0x40 -#define GOT_FOCUS 0x80 - -/* - * Symbolic values for the active parts of a slider. These are - * the values that may be returned by the ScaleElement procedure. - */ - -#define OTHER 0 -#define TROUGH1 1 -#define SLIDER 2 -#define TROUGH2 3 - -/* - * Space to leave between scale area and text, and between text and - * edge of window. - */ - -#define SPACING 2 - -/* - * How many characters of space to provide when formatting the - * scale's value: - */ - -#define PRINT_CHARS 150 - -/* - * Declaration of procedures used in the implementation of the scrollbar - * widget. - */ - -EXTERN void TkEventuallyRedrawScale _ANSI_ARGS_((TkScale *scalePtr, - int what)); -EXTERN double TkRoundToResolution _ANSI_ARGS_((TkScale *scalePtr, - double value)); -EXTERN TkScale * TkpCreateScale _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkpDestroyScale _ANSI_ARGS_((TkScale *scalePtr)); -EXTERN void TkpDisplayScale _ANSI_ARGS_((ClientData clientData)); -EXTERN double TkpPixelToValue _ANSI_ARGS_((TkScale *scalePtr, - int x, int y)); -EXTERN int TkpScaleElement _ANSI_ARGS_((TkScale *scalePtr, - int x, int y)); -EXTERN void TkpSetScaleValue _ANSI_ARGS_((TkScale *scalePtr, - double value, int setVar, int invokeCommand)); -EXTERN int TkpValueToPixel _ANSI_ARGS_((TkScale *scalePtr, - double value)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKSCALE */ diff --git a/generic/tkScrollbar.c b/generic/tkScrollbar.c deleted file mode 100644 index 0b90160..0000000 --- a/generic/tkScrollbar.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * tkScrollbar.c -- - * - * This module implements a scrollbar widgets for the Tk - * toolkit. A scrollbar displays a slider and two arrows; - * mouse clicks on features within the scrollbar cause - * scrolling commands to be invoked. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkScrollbar.c,v 1.2 1998/09/14 18:23:17 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkScrollbar.h" -#include "default.h" - -/* - * Information used for argv parsing. - */ - -Tk_ConfigSpec tkpScrollbarConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCROLLBAR_ACTIVE_BG_COLOR, Tk_Offset(TkScrollbar, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(TkScrollbar, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", - DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(TkScrollbar, activeRelief), 0}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCROLLBAR_BG_COLOR, Tk_Offset(TkScrollbar, bgBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCROLLBAR_BG_MONO, Tk_Offset(TkScrollbar, bgBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(TkScrollbar, borderWidth), 0}, - {TK_CONFIG_STRING, "-command", "command", "Command", - DEF_SCROLLBAR_COMMAND, Tk_Offset(TkScrollbar, command), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_SCROLLBAR_CURSOR, Tk_Offset(TkScrollbar, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth", - "BorderWidth", DEF_SCROLLBAR_EL_BORDER_WIDTH, - Tk_Offset(TkScrollbar, elementBorderWidth), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG, - Tk_Offset(TkScrollbar, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_SCROLLBAR_HIGHLIGHT, - Tk_Offset(TkScrollbar, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(TkScrollbar, highlightWidth), 0}, - {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", - DEF_SCROLLBAR_JUMP, Tk_Offset(TkScrollbar, jump), 0}, - {TK_CONFIG_UID, "-orient", "orient", "Orient", - DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, orientUid), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_SCROLLBAR_RELIEF, Tk_Offset(TkScrollbar, relief), 0}, - {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", - DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(TkScrollbar, repeatDelay), 0}, - {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", - DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(TkScrollbar, repeatInterval), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(TkScrollbar, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(TkScrollbar, troughColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(TkScrollbar, troughColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_SCROLLBAR_WIDTH, Tk_Offset(TkScrollbar, width), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp, - TkScrollbar *scrollPtr, int argc, char **argv, - int flags)); -static void ScrollbarCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *, int argc, char **argv)); - -/* - *-------------------------------------------------------------- - * - * Tk_ScrollbarCmd -- - * - * This procedure is invoked to process the "scrollbar" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_ScrollbarCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - register TkScrollbar *scrollPtr; - Tk_Window new; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - Tk_SetClass(new, "Scrollbar"); - scrollPtr = TkpCreateScrollbar(new); - - TkSetClassProcs(new, &tkpScrollbarProcs, (ClientData) scrollPtr); - - /* - * Initialize fields that won't be initialized by ConfigureScrollbar, - * or which ConfigureScrollbar expects to have reasonable values - * (e.g. resource pointers). - */ - - scrollPtr->tkwin = new; - scrollPtr->display = Tk_Display(new); - scrollPtr->interp = interp; - scrollPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, - (ClientData) scrollPtr, ScrollbarCmdDeletedProc); - scrollPtr->orientUid = NULL; - scrollPtr->vertical = 0; - scrollPtr->width = 0; - scrollPtr->command = NULL; - scrollPtr->commandSize = 0; - scrollPtr->repeatDelay = 0; - scrollPtr->repeatInterval = 0; - scrollPtr->borderWidth = 0; - scrollPtr->bgBorder = NULL; - scrollPtr->activeBorder = NULL; - scrollPtr->troughColorPtr = NULL; - scrollPtr->relief = TK_RELIEF_FLAT; - scrollPtr->highlightWidth = 0; - scrollPtr->highlightBgColorPtr = NULL; - scrollPtr->highlightColorPtr = NULL; - scrollPtr->inset = 0; - scrollPtr->elementBorderWidth = -1; - scrollPtr->arrowLength = 0; - scrollPtr->sliderFirst = 0; - scrollPtr->sliderLast = 0; - scrollPtr->activeField = 0; - scrollPtr->activeRelief = TK_RELIEF_RAISED; - scrollPtr->totalUnits = 0; - scrollPtr->windowUnits = 0; - scrollPtr->firstUnit = 0; - scrollPtr->lastUnit = 0; - scrollPtr->firstFraction = 0.0; - scrollPtr->lastFraction = 0.0; - scrollPtr->cursor = None; - scrollPtr->takeFocus = NULL; - scrollPtr->flags = 0; - - if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) { - Tk_DestroyWindow(scrollPtr->tkwin); - return TCL_ERROR; - } - - interp->result = Tk_PathName(scrollPtr->tkwin); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * ScrollbarWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -ScrollbarWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about scrollbar - * widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) scrollPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { - int oldActiveField; - if (argc == 2) { - switch (scrollPtr->activeField) { - case TOP_ARROW: interp->result = "arrow1"; break; - case SLIDER: interp->result = "slider"; break; - case BOTTOM_ARROW: interp->result = "arrow2"; break; - } - goto done; - } - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " activate element\"", (char *) NULL); - goto error; - } - c = argv[2][0]; - length = strlen(argv[2]); - oldActiveField = scrollPtr->activeField; - if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) { - scrollPtr->activeField = TOP_ARROW; - } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) { - scrollPtr->activeField = BOTTOM_ARROW; - } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) { - scrollPtr->activeField = SLIDER; - } else { - scrollPtr->activeField = OUTSIDE; - } - if (oldActiveField != scrollPtr->activeField) { - TkScrollbarEventuallyRedraw(scrollPtr); - } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, scrollPtr->tkwin, - tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, - tkpScrollbarConfigSpecs, (char *) scrollPtr, - (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, - tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0); - } else { - result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) { - int xDelta, yDelta, pixels, length; - double fraction; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delta xDelta yDelta\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) { - goto error; - } - if (scrollPtr->vertical) { - pixels = yDelta; - length = Tk_Height(scrollPtr->tkwin) - 1 - - 2*(scrollPtr->arrowLength + scrollPtr->inset); - } else { - pixels = xDelta; - length = Tk_Width(scrollPtr->tkwin) - 1 - - 2*(scrollPtr->arrowLength + scrollPtr->inset); - } - if (length == 0) { - fraction = 0.0; - } else { - fraction = ((double) pixels / (double) length); - } - sprintf(interp->result, "%g", fraction); - } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) { - int x, y, pos, length; - double fraction; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " fraction x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - if (scrollPtr->vertical) { - pos = y - (scrollPtr->arrowLength + scrollPtr->inset); - length = Tk_Height(scrollPtr->tkwin) - 1 - - 2*(scrollPtr->arrowLength + scrollPtr->inset); - } else { - pos = x - (scrollPtr->arrowLength + scrollPtr->inset); - length = Tk_Width(scrollPtr->tkwin) - 1 - - 2*(scrollPtr->arrowLength + scrollPtr->inset); - } - if (length == 0) { - fraction = 0.0; - } else { - fraction = ((double) pos / (double) length); - } - if (fraction < 0) { - fraction = 0; - } else if (fraction > 1.0) { - fraction = 1.0; - } - sprintf(interp->result, "%g", fraction); - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get\"", (char *) NULL); - goto error; - } - if (scrollPtr->flags & NEW_STYLE_COMMANDS) { - char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE]; - - Tcl_PrintDouble(interp, scrollPtr->firstFraction, first); - Tcl_PrintDouble(interp, scrollPtr->lastFraction, last); - Tcl_AppendResult(interp, first, " ", last, (char *) NULL); - } else { - sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits, - scrollPtr->windowUnits, scrollPtr->firstUnit, - scrollPtr->lastUnit); - } - } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { - int x, y, thing; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " identify x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - thing = TkpScrollbarPosition(scrollPtr, x,y); - switch (thing) { - case TOP_ARROW: interp->result = "arrow1"; break; - case TOP_GAP: interp->result = "trough1"; break; - case SLIDER: interp->result = "slider"; break; - case BOTTOM_GAP: interp->result = "trough2"; break; - case BOTTOM_ARROW: interp->result = "arrow2"; break; - } - } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { - int totalUnits, windowUnits, firstUnit, lastUnit; - - if (argc == 4) { - double first, last; - - if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) { - goto error; - } - if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) { - goto error; - } - if (first < 0) { - scrollPtr->firstFraction = 0; - } else if (first > 1.0) { - scrollPtr->firstFraction = 1.0; - } else { - scrollPtr->firstFraction = first; - } - if (last < scrollPtr->firstFraction) { - scrollPtr->lastFraction = scrollPtr->firstFraction; - } else if (last > 1.0) { - scrollPtr->lastFraction = 1.0; - } else { - scrollPtr->lastFraction = last; - } - scrollPtr->flags |= NEW_STYLE_COMMANDS; - } else if (argc == 6) { - if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) { - goto error; - } - if (totalUnits < 0) { - totalUnits = 0; - } - if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) { - goto error; - } - if (windowUnits < 0) { - windowUnits = 0; - } - if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) { - goto error; - } - if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) { - goto error; - } - if (totalUnits > 0) { - if (lastUnit < firstUnit) { - lastUnit = firstUnit; - } - } else { - firstUnit = lastUnit = 0; - } - scrollPtr->totalUnits = totalUnits; - scrollPtr->windowUnits = windowUnits; - scrollPtr->firstUnit = firstUnit; - scrollPtr->lastUnit = lastUnit; - if (scrollPtr->totalUnits == 0) { - scrollPtr->firstFraction = 0.0; - scrollPtr->lastFraction = 1.0; - } else { - scrollPtr->firstFraction = ((double) firstUnit)/totalUnits; - scrollPtr->lastFraction = ((double) (lastUnit+1))/totalUnits; - } - scrollPtr->flags &= ~NEW_STYLE_COMMANDS; - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " set firstFraction lastFraction\" or \"", - argv[0], - " set totalUnits windowUnits firstUnit lastUnit\"", - (char *) NULL); - goto error; - } - TkpComputeScrollbarGeometry(scrollPtr); - TkScrollbarEventuallyRedraw(scrollPtr); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be activate, cget, configure, delta, fraction, ", - "get, identify, or set", (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) scrollPtr); - return result; - - error: - Tcl_Release((ClientData) scrollPtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureScrollbar -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a scrollbar widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for scrollPtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkScrollbar *scrollPtr; /* Information about widget; may or - * may not already have values for - * some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to - * Tk_ConfigureWidget. */ -{ - size_t length; - - if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, tkpScrollbarConfigSpecs, - argc, argv, (char *) scrollPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few options need special processing, such as parsing the - * orientation or setting the background from a 3-D border. - */ - - length = strlen(scrollPtr->orientUid); - if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { - scrollPtr->vertical = 1; - } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { - scrollPtr->vertical = 0; - } else { - Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, - "\": must be vertical or horizontal", (char *) NULL); - return TCL_ERROR; - } - - if (scrollPtr->command != NULL) { - scrollPtr->commandSize = strlen(scrollPtr->command); - } else { - scrollPtr->commandSize = 0; - } - - /* - * Configure platform specific options. - */ - - TkpConfigureScrollbar(scrollPtr); - - /* - * Register the desired geometry for the window (leave enough space - * for the two arrows plus a minimum-size slider, plus border around - * the whole window, if any). Then arrange for the window to be - * redisplayed. - */ - - TkpComputeScrollbarGeometry(scrollPtr); - TkScrollbarEventuallyRedraw(scrollPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkScrollbarEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on scrollbars. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -void -TkScrollbarEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - TkScrollbar *scrollPtr = (TkScrollbar *) clientData; - - if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { - TkScrollbarEventuallyRedraw(scrollPtr); - } else if (eventPtr->type == DestroyNotify) { - TkpDestroyScrollbar(scrollPtr); - if (scrollPtr->tkwin != NULL) { - scrollPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(scrollPtr->interp, - scrollPtr->widgetCmd); - } - if (scrollPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(TkpDisplayScrollbar, (ClientData) scrollPtr); - } - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. - */ - - Tk_FreeOptions(tkpScrollbarConfigSpecs, (char *) scrollPtr, - scrollPtr->display, 0); - Tcl_EventuallyFree((ClientData) scrollPtr, TCL_DYNAMIC); - } else if (eventPtr->type == ConfigureNotify) { - TkpComputeScrollbarGeometry(scrollPtr); - TkScrollbarEventuallyRedraw(scrollPtr); - } else if (eventPtr->type == FocusIn) { - if (eventPtr->xfocus.detail != NotifyInferior) { - scrollPtr->flags |= GOT_FOCUS; - if (scrollPtr->highlightWidth > 0) { - TkScrollbarEventuallyRedraw(scrollPtr); - } - } - } else if (eventPtr->type == FocusOut) { - if (eventPtr->xfocus.detail != NotifyInferior) { - scrollPtr->flags &= ~GOT_FOCUS; - if (scrollPtr->highlightWidth > 0) { - TkScrollbarEventuallyRedraw(scrollPtr); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * ScrollbarCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -ScrollbarCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkScrollbar *scrollPtr = (TkScrollbar *) clientData; - Tk_Window tkwin = scrollPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - scrollPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * TkScrollbarEventuallyRedraw -- - * - * Arrange for one or more of the fields of a scrollbar - * to be redrawn. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkScrollbarEventuallyRedraw(scrollPtr) - register TkScrollbar *scrollPtr; /* Information about widget. */ -{ - if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) { - return; - } - if ((scrollPtr->flags & REDRAW_PENDING) == 0) { - Tcl_DoWhenIdle(TkpDisplayScrollbar, (ClientData) scrollPtr); - scrollPtr->flags |= REDRAW_PENDING; - } -} diff --git a/generic/tkScrollbar.h b/generic/tkScrollbar.h deleted file mode 100644 index a1f3d4a..0000000 --- a/generic/tkScrollbar.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * tkScrollbar.h -- - * - * Declarations of types and functions used to implement - * the scrollbar widget. - * - * Copyright (c) 1996 by Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkScrollbar.h,v 1.4 1998/09/14 18:23:17 stanton Exp $ - */ - -#ifndef _TKSCROLLBAR -#define _TKSCROLLBAR - -#ifndef _TKINT -#include "tkInt.h" -#endif - -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - -/* - * A data structure of the following type is kept for each scrollbar - * widget. - */ - -typedef struct TkScrollbar { - Tk_Window tkwin; /* Window that embodies the scrollbar. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display containing widget. Used, among - * other things, so that resources can be - * freed even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ - Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */ - Tk_Uid orientUid; /* Orientation for window ("vertical" or - * "horizontal"). */ - int vertical; /* Non-zero means vertical orientation - * requested, zero means horizontal. */ - int width; /* Desired narrow dimension of scrollbar, - * in pixels. */ - char *command; /* Command prefix to use when invoking - * scrolling commands. NULL means don't - * invoke commands. Malloc'ed. */ - int commandSize; /* Number of non-NULL bytes in command. */ - int repeatDelay; /* How long to wait before auto-repeating - * on scrolling actions (in ms). */ - int repeatInterval; /* Interval between autorepeats (in ms). */ - int jump; /* Value of -jump option. */ - - /* - * Information used when displaying widget: - */ - - int borderWidth; /* Width of 3-D borders. */ - Tk_3DBorder bgBorder; /* Used for drawing background (all flat - * surfaces except for trough). */ - Tk_3DBorder activeBorder; /* For drawing backgrounds when active (i.e. - * when mouse is positioned over element). */ - XColor *troughColorPtr; /* Color for drawing trough. */ - int relief; /* Indicates whether window as a whole is - * raised, sunken, or flat. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - int inset; /* Total width of all borders, including - * traversal highlight and 3-D border. - * Indicates how much interior stuff must - * be offset from outside edges to leave - * room for borders. */ - int elementBorderWidth; /* Width of border to draw around elements - * inside scrollbar (arrows and slider). - * -1 means use borderWidth. */ - int arrowLength; /* Length of arrows along long dimension of - * scrollbar, including space for a small gap - * between the arrow and the slider. - * Recomputed on window size changes. */ - int sliderFirst; /* Pixel coordinate of top or left edge - * of slider area, including border. */ - int sliderLast; /* Coordinate of pixel just after bottom - * or right edge of slider area, including - * border. */ - int activeField; /* Names field to be displayed in active - * colors, such as TOP_ARROW, or 0 for - * no field. */ - int activeRelief; /* Value of -activeRelief option: relief - * to use for active element. */ - - /* - * Information describing the application related to the scrollbar. - * This information is provided by the application by invoking the - * "set" widget command. This information can now be provided in - * two ways: the "old" form (totalUnits, windowUnits, firstUnit, - * and lastUnit), or the "new" form (firstFraction and lastFraction). - * FirstFraction and lastFraction will always be valid, but - * the old-style information is only valid if the NEW_STYLE_COMMANDS - * flag is 0. - */ - - int totalUnits; /* Total dimension of application, in - * units. Valid only if the NEW_STYLE_COMMANDS - * flag isn't set. */ - int windowUnits; /* Maximum number of units that can be - * displayed in the window at once. Valid - * only if the NEW_STYLE_COMMANDS flag isn't - * set. */ - int firstUnit; /* Number of last unit visible in - * application's window. Valid only if the - * NEW_STYLE_COMMANDS flag isn't set. */ - int lastUnit; /* Index of last unit visible in window. - * Valid only if the NEW_STYLE_COMMANDS - * flag isn't set. */ - double firstFraction; /* Position of first visible thing in window, - * specified as a fraction between 0 and - * 1.0. */ - double lastFraction; /* Position of last visible thing in window, - * specified as a fraction between 0 and - * 1.0. */ - - /* - * Miscellaneous information: - */ - - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - int flags; /* Various flags; see below for - * definitions. */ -} TkScrollbar; - -/* - * Legal values for "activeField" field of Scrollbar structures. These - * are also the return values from the ScrollbarPosition procedure. - */ - -#define OUTSIDE 0 -#define TOP_ARROW 1 -#define TOP_GAP 2 -#define SLIDER 3 -#define BOTTOM_GAP 4 -#define BOTTOM_ARROW 5 - -/* - * Flag bits for scrollbars: - * - * REDRAW_PENDING: Non-zero means a DoWhenIdle handler - * has already been queued to redraw - * this window. - * NEW_STYLE_COMMANDS: Non-zero means the new style of commands - * should be used to communicate with the - * widget: ".t yview scroll 2 lines", instead - * of ".t yview 40", for example. - * GOT_FOCUS: Non-zero means this window has the input - * focus. - */ - -#define REDRAW_PENDING 1 -#define NEW_STYLE_COMMANDS 2 -#define GOT_FOCUS 4 - -/* - * Declaration of scrollbar class procedures structure. - */ - -extern TkClassProcs tkpScrollbarProcs; - -/* - * Declaration of scrollbar configuration options. - */ - -extern Tk_ConfigSpec tkpScrollbarConfigSpecs[]; - -/* - * Declaration of procedures used in the implementation of the scrollbar - * widget. - */ - -EXTERN void TkScrollbarEventProc _ANSI_ARGS_(( - ClientData clientData, XEvent *eventPtr)); -EXTERN void TkScrollbarEventuallyRedraw _ANSI_ARGS_(( - TkScrollbar *scrollPtr)); -EXTERN void TkpComputeScrollbarGeometry _ANSI_ARGS_(( - TkScrollbar *scrollPtr)); -EXTERN TkScrollbar * TkpCreateScrollbar _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkpDestroyScrollbar _ANSI_ARGS_(( - TkScrollbar *scrollPtr)); -EXTERN void TkpDisplayScrollbar _ANSI_ARGS_(( - ClientData clientData)); -EXTERN void TkpConfigureScrollbar _ANSI_ARGS_(( - TkScrollbar *scrollPtr)); -EXTERN int TkpScrollbarPosition _ANSI_ARGS_(( - TkScrollbar *scrollPtr, int x, int y)); - -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLIMPORT - -#endif /* _TKSCROLLBAR */ diff --git a/generic/tkSelect.c b/generic/tkSelect.c deleted file mode 100644 index 01e8af4..0000000 --- a/generic/tkSelect.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * tkSelect.c -- - * - * This file manages the selection for the Tk toolkit, - * translating between the standard X ICCCM conventions - * and Tcl commands. - * - * Copyright (c) 1990-1993 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkSelect.c,v 1.2 1998/09/14 18:23:17 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkSelect.h" - -/* - * When a selection handler is set up by invoking "selection handle", - * one of the following data structures is set up to hold information - * about the command to invoke and its interpreter. - */ - -typedef struct { - Tcl_Interp *interp; /* Interpreter in which to invoke command. */ - int cmdLength; /* # of non-NULL bytes in command. */ - char command[4]; /* Command to invoke. Actual space is - * allocated as large as necessary. This - * must be the last entry in the structure. */ -} CommandInfo; - -/* - * When selection ownership is claimed with the "selection own" Tcl command, - * one of the following structures is created to record the Tcl command - * to be executed when the selection is lost again. - */ - -typedef struct LostCommand { - Tcl_Interp *interp; /* Interpreter in which to invoke command. */ - char command[4]; /* Command to invoke. Actual space is - * allocated as large as necessary. This - * must be the last entry in the structure. */ -} LostCommand; - -/* - * Shared variables: - */ - -TkSelInProgress *pendingPtr = NULL; - /* Topmost search in progress, or - * NULL if none. */ - -/* - * Forward declarations for procedures defined in this file: - */ - -static int HandleTclCommand _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static void LostSelection _ANSI_ARGS_((ClientData clientData)); -static int SelGetProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, char *portion)); - -/* - *-------------------------------------------------------------- - * - * Tk_CreateSelHandler -- - * - * This procedure is called to register a procedure - * as the handler for selection requests of a particular - * target type on a particular window for a particular - * selection. - * - * Results: - * None. - * - * Side effects: - * In the future, whenever the selection is in tkwin's - * window and someone requests the selection in the - * form given by target, proc will be invoked to provide - * part or all of the selection in the given form. If - * there was already a handler declared for the given - * window, target and selection type, then it is replaced. - * Proc should have the following form: - * - * int - * proc(clientData, offset, buffer, maxBytes) - * ClientData clientData; - * int offset; - * char *buffer; - * int maxBytes; - * { - * } - * - * The clientData argument to proc will be the same as - * the clientData argument to this procedure. The offset - * argument indicates which portion of the selection to - * return: skip the first offset bytes. Buffer is a - * pointer to an area in which to place the converted - * selection, and maxBytes gives the number of bytes - * available at buffer. Proc should place the selection - * in buffer as a string, and return a count of the number - * of bytes of selection actually placed in buffer (not - * including the terminating NULL character). If the - * return value equals maxBytes, this is a sign that there - * is probably still more selection information available. - * - *-------------------------------------------------------------- - */ - -void -Tk_CreateSelHandler(tkwin, selection, target, proc, clientData, format) - Tk_Window tkwin; /* Token for window. */ - Atom selection; /* Selection to be handled. */ - Atom target; /* The kind of selection conversions - * that can be handled by proc, - * e.g. TARGETS or STRING. */ - Tk_SelectionProc *proc; /* Procedure to invoke to convert - * selection to type "target". */ - ClientData clientData; /* Value to pass to proc. */ - Atom format; /* Format in which the selection - * information should be returned to - * the requestor. XA_STRING is best by - * far, but anything listed in the ICCCM - * will be tolerated (blech). */ -{ - register TkSelHandler *selPtr; - TkWindow *winPtr = (TkWindow *) tkwin; - - if (winPtr->dispPtr->multipleAtom == None) { - TkSelInit(tkwin); - } - - /* - * See if there's already a handler for this target and selection on - * this window. If so, re-use it. If not, create a new one. - */ - - for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) { - if (selPtr == NULL) { - selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler)); - selPtr->nextPtr = winPtr->selHandlerList; - winPtr->selHandlerList = selPtr; - break; - } - if ((selPtr->selection == selection) && (selPtr->target == target)) { - - /* - * Special case: when replacing handler created by - * "selection handle", free up memory. Should there be a - * callback to allow other clients to do this too? - */ - - if (selPtr->proc == HandleTclCommand) { - ckfree((char *) selPtr->clientData); - } - break; - } - } - selPtr->selection = selection; - selPtr->target = target; - selPtr->format = format; - selPtr->proc = proc; - selPtr->clientData = clientData; - if (format == XA_STRING) { - selPtr->size = 8; - } else { - selPtr->size = 32; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DeleteSelHandler -- - * - * Remove the selection handler for a given window, target, and - * selection, if it exists. - * - * Results: - * None. - * - * Side effects: - * The selection handler for tkwin and target is removed. If there - * is no such handler then nothing happens. - * - *---------------------------------------------------------------------- - */ - -void -Tk_DeleteSelHandler(tkwin, selection, target) - Tk_Window tkwin; /* Token for window. */ - Atom selection; /* The selection whose handler - * is to be removed. */ - Atom target; /* The target whose selection - * handler is to be removed. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - register TkSelHandler *selPtr, *prevPtr; - register TkSelInProgress *ipPtr; - - /* - * Find the selection handler to be deleted, or return if it doesn't - * exist. - */ - - for (selPtr = winPtr->selHandlerList, prevPtr = NULL; ; - prevPtr = selPtr, selPtr = selPtr->nextPtr) { - if (selPtr == NULL) { - return; - } - if ((selPtr->selection == selection) && (selPtr->target == target)) { - break; - } - } - - /* - * If ConvertSelection is processing this handler, tell it that the - * handler is dead. - */ - - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { - if (ipPtr->selPtr == selPtr) { - ipPtr->selPtr = NULL; - } - } - - /* - * Free resources associated with the handler. - */ - - if (prevPtr == NULL) { - winPtr->selHandlerList = selPtr->nextPtr; - } else { - prevPtr->nextPtr = selPtr->nextPtr; - } - if (selPtr->proc == HandleTclCommand) { - ckfree((char *) selPtr->clientData); - } - ckfree((char *) selPtr); -} - -/* - *-------------------------------------------------------------- - * - * Tk_OwnSelection -- - * - * Arrange for tkwin to become the owner of a selection. - * - * Results: - * None. - * - * Side effects: - * From now on, requests for the selection will be directed - * to procedures associated with tkwin (they must have been - * declared with calls to Tk_CreateSelHandler). When the - * selection is lost by this window, proc will be invoked - * (see the manual entry for details). This procedure may - * invoke callbacks, including Tcl scripts, so any calling - * function should be reentrant at the point where - * Tk_OwnSelection is invoked. - * - *-------------------------------------------------------------- - */ - -void -Tk_OwnSelection(tkwin, selection, proc, clientData) - Tk_Window tkwin; /* Window to become new selection - * owner. */ - Atom selection; /* Selection that window should own. */ - Tk_LostSelProc *proc; /* Procedure to call when selection - * is taken away from tkwin. */ - ClientData clientData; /* Arbitrary one-word argument to - * pass to proc. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkSelectionInfo *infoPtr; - Tk_LostSelProc *clearProc = NULL; - ClientData clearData = NULL; /* Initialization needed only to - * prevent compiler warning. */ - - - if (dispPtr->multipleAtom == None) { - TkSelInit(tkwin); - } - Tk_MakeWindowExist(tkwin); - - /* - * This code is somewhat tricky. First, we find the specified selection - * on the selection list. If the previous owner is in this process, and - * is a different window, then we need to invoke the clearProc. However, - * it's dangerous to call the clearProc right now, because it could - * invoke a Tcl script that wrecks the current state (e.g. it could - * delete the window). To be safe, defer the call until the end of the - * procedure when we no longer care about the state. - */ - - for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; - infoPtr = infoPtr->nextPtr) { - if (infoPtr->selection == selection) { - break; - } - } - if (infoPtr == NULL) { - infoPtr = (TkSelectionInfo*) ckalloc(sizeof(TkSelectionInfo)); - infoPtr->selection = selection; - infoPtr->nextPtr = dispPtr->selectionInfoPtr; - dispPtr->selectionInfoPtr = infoPtr; - } else if (infoPtr->clearProc != NULL) { - if (infoPtr->owner != tkwin) { - clearProc = infoPtr->clearProc; - clearData = infoPtr->clearData; - } else if (infoPtr->clearProc == LostSelection) { - /* - * If the selection handler is one created by "selection own", - * be sure to free the record for it; otherwise there will be - * a memory leak. - */ - - ckfree((char *) infoPtr->clearData); - } - } - - infoPtr->owner = tkwin; - infoPtr->serial = NextRequest(winPtr->display); - infoPtr->clearProc = proc; - infoPtr->clearData = clientData; - - /* - * Note that we are using CurrentTime, even though ICCCM recommends against - * this practice (the problem is that we don't necessarily have a valid - * time to use). We will not be able to retrieve a useful timestamp for - * the TIMESTAMP target later. - */ - - infoPtr->time = CurrentTime; - - /* - * Note that we are not checking to see if the selection claim succeeded. - * If the ownership does not change, then the clearProc may never be - * invoked, and we will return incorrect information when queried for the - * current selection owner. - */ - - XSetSelectionOwner(winPtr->display, infoPtr->selection, winPtr->window, - infoPtr->time); - - /* - * Now that we are done, we can invoke clearProc without running into - * reentrancy problems. - */ - - if (clearProc != NULL) { - (*clearProc)(clearData); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ClearSelection -- - * - * Eliminate the specified selection on tkwin's display, if there is one. - * - * Results: - * None. - * - * Side effects: - * The specified selection is cleared, so that future requests to retrieve - * it will fail until some application owns it again. This procedure - * invokes callbacks, possibly including Tcl scripts, so any calling - * function should be reentrant at the point Tk_ClearSelection is invoked. - * - *---------------------------------------------------------------------- - */ - -void -Tk_ClearSelection(tkwin, selection) - Tk_Window tkwin; /* Window that selects a display. */ - Atom selection; /* Selection to be cancelled. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkSelectionInfo *infoPtr; - TkSelectionInfo *prevPtr; - TkSelectionInfo *nextPtr; - Tk_LostSelProc *clearProc = NULL; - ClientData clearData = NULL; /* Initialization needed only to - * prevent compiler warning. */ - - if (dispPtr->multipleAtom == None) { - TkSelInit(tkwin); - } - - for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL; - infoPtr != NULL; infoPtr = nextPtr) { - nextPtr = infoPtr->nextPtr; - if (infoPtr->selection == selection) { - if (prevPtr == NULL) { - dispPtr->selectionInfoPtr = nextPtr; - } else { - prevPtr->nextPtr = nextPtr; - } - break; - } - prevPtr = infoPtr; - } - - if (infoPtr != NULL) { - clearProc = infoPtr->clearProc; - clearData = infoPtr->clearData; - ckfree((char *) infoPtr); - } - XSetSelectionOwner(winPtr->display, selection, None, CurrentTime); - - if (clearProc != NULL) { - (*clearProc)(clearData); - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_GetSelection -- - * - * Retrieve the value of a selection and pass it off (in - * pieces, possibly) to a given procedure. - * - * Results: - * The return value is a standard Tcl return value. - * If an error occurs (such as no selection exists) - * then an error message is left in interp->result. - * - * Side effects: - * The standard X11 protocols are used to retrieve the - * selection. When it arrives, it is passed to proc. If - * the selection is very large, it will be passed to proc - * in several pieces. Proc should have the following - * structure: - * - * int - * proc(clientData, interp, portion) - * ClientData clientData; - * Tcl_Interp *interp; - * char *portion; - * { - * } - * - * The interp and clientData arguments to proc will be the - * same as the corresponding arguments to Tk_GetSelection. - * The portion argument points to a character string - * containing part of the selection, and numBytes indicates - * the length of the portion, not including the terminating - * NULL character. If the selection arrives in several pieces, - * the "portion" arguments in separate calls will contain - * successive parts of the selection. Proc should normally - * return TCL_OK. If it detects an error then it should return - * TCL_ERROR and leave an error message in interp->result; the - * remainder of the selection retrieval will be aborted. - * - *-------------------------------------------------------------- - */ - -int -Tk_GetSelection(interp, tkwin, selection, target, proc, clientData) - Tcl_Interp *interp; /* Interpreter to use for reporting - * errors. */ - Tk_Window tkwin; /* Window on whose behalf to retrieve - * the selection (determines display - * from which to retrieve). */ - Atom selection; /* Selection to retrieve. */ - Atom target; /* Desired form in which selection - * is to be returned. */ - Tk_GetSelProc *proc; /* Procedure to call to process the - * selection, once it has been retrieved. */ - ClientData clientData; /* Arbitrary value to pass to proc. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkSelectionInfo *infoPtr; - - if (dispPtr->multipleAtom == None) { - TkSelInit(tkwin); - } - - /* - * If the selection is owned by a window managed by this - * process, then call the retrieval procedure directly, - * rather than going through the X server (it's dangerous - * to go through the X server in this case because it could - * result in deadlock if an INCR-style selection results). - */ - - for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL; - infoPtr = infoPtr->nextPtr) { - if (infoPtr->selection == selection) - break; - } - if (infoPtr != NULL) { - register TkSelHandler *selPtr; - int offset, result, count; - char buffer[TK_SEL_BYTES_AT_ONCE+1]; - TkSelInProgress ip; - - for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList; - selPtr != NULL; selPtr = selPtr->nextPtr) { - if ((selPtr->target == target) - && (selPtr->selection == selection)) { - break; - } - } - if (selPtr == NULL) { - Atom type; - - count = TkSelDefaultSelection(infoPtr, target, buffer, - TK_SEL_BYTES_AT_ONCE, &type); - if (count > TK_SEL_BYTES_AT_ONCE) { - panic("selection handler returned too many bytes"); - } - if (count < 0) { - goto cantget; - } - buffer[count] = 0; - result = (*proc)(clientData, interp, buffer); - } else { - offset = 0; - result = TCL_OK; - ip.selPtr = selPtr; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; - while (1) { - count = (selPtr->proc)(selPtr->clientData, offset, buffer, - TK_SEL_BYTES_AT_ONCE); - if ((count < 0) || (ip.selPtr == NULL)) { - pendingPtr = ip.nextPtr; - goto cantget; - } - if (count > TK_SEL_BYTES_AT_ONCE) { - panic("selection handler returned too many bytes"); - } - buffer[count] = '\0'; - result = (*proc)(clientData, interp, buffer); - if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE) - || (ip.selPtr == NULL)) { - break; - } - offset += count; - } - pendingPtr = ip.nextPtr; - } - return result; - } - - /* - * The selection is owned by some other process. - */ - - return TkSelGetSelection(interp, tkwin, selection, target, proc, - clientData); - - cantget: - Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), - " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), - "\" not defined", (char *) NULL); - return TCL_ERROR; -} - -/* - *-------------------------------------------------------------- - * - * Tk_SelectionCmd -- - * - * This procedure is invoked to process the "selection" Tcl - * command. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_SelectionCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - char *path = NULL; - Atom selection; - char *selName = NULL; - int c, count; - size_t length; - char **args; - - if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); - return TCL_ERROR; - } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) { - for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - if (count < 2) { - Tcl_AppendResult(interp, "value for \"", *args, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) { - path = args[1]; - } else if ((c == 's') - && (strncmp(args[0], "-selection", length) == 0)) { - selName = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - if (count == 1) { - path = args[0]; - } else if (count > 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " clear ?options?\"", (char *) NULL); - return TCL_ERROR; - } - if (path != NULL) { - tkwin = Tk_NameToWindow(interp, path, tkwin); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - if (selName != NULL) { - selection = Tk_InternAtom(tkwin, selName); - } else { - selection = XA_PRIMARY; - } - - Tk_ClearSelection(tkwin, selection); - return TCL_OK; - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - Atom target; - char *targetName = NULL; - Tcl_DString selBytes; - int result; - - for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - if (count < 2) { - Tcl_AppendResult(interp, "value for \"", *args, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) { - path = args[1]; - } else if ((c == 's') - && (strncmp(args[0], "-selection", length) == 0)) { - selName = args[1]; - } else if ((c == 't') - && (strncmp(args[0], "-type", length) == 0)) { - targetName = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - if (path != NULL) { - tkwin = Tk_NameToWindow(interp, path, tkwin); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - if (selName != NULL) { - selection = Tk_InternAtom(tkwin, selName); - } else { - selection = XA_PRIMARY; - } - if (count > 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " get ?options?\"", (char *) NULL); - return TCL_ERROR; - } else if (count == 1) { - target = Tk_InternAtom(tkwin, args[0]); - } else if (targetName != NULL) { - target = Tk_InternAtom(tkwin, targetName); - } else { - target = XA_STRING; - } - - Tcl_DStringInit(&selBytes); - result = Tk_GetSelection(interp, tkwin, selection, target, SelGetProc, - (ClientData) &selBytes); - if (result == TCL_OK) { - Tcl_DStringResult(interp, &selBytes); - } else { - Tcl_DStringFree(&selBytes); - } - return result; - } else if ((c == 'h') && (strncmp(argv[1], "handle", length) == 0)) { - Atom target, format; - char *targetName = NULL; - char *formatName = NULL; - register CommandInfo *cmdInfoPtr; - int cmdLength; - - for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - if (count < 2) { - Tcl_AppendResult(interp, "value for \"", *args, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == 'f') && (strncmp(args[0], "-format", length) == 0)) { - formatName = args[1]; - } else if ((c == 's') - && (strncmp(args[0], "-selection", length) == 0)) { - selName = args[1]; - } else if ((c == 't') - && (strncmp(args[0], "-type", length) == 0)) { - targetName = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - - if ((count < 2) || (count > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " handle ?options? window command\"", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_NameToWindow(interp, args[0], tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - if (selName != NULL) { - selection = Tk_InternAtom(tkwin, selName); - } else { - selection = XA_PRIMARY; - } - - if (count > 2) { - target = Tk_InternAtom(tkwin, args[2]); - } else if (targetName != NULL) { - target = Tk_InternAtom(tkwin, targetName); - } else { - target = XA_STRING; - } - if (count > 3) { - format = Tk_InternAtom(tkwin, args[3]); - } else if (formatName != NULL) { - format = Tk_InternAtom(tkwin, formatName); - } else { - format = XA_STRING; - } - cmdLength = strlen(args[1]); - if (cmdLength == 0) { - Tk_DeleteSelHandler(tkwin, selection, target); - } else { - cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) ( - sizeof(CommandInfo) - 3 + cmdLength)); - cmdInfoPtr->interp = interp; - cmdInfoPtr->cmdLength = cmdLength; - strcpy(cmdInfoPtr->command, args[1]); - Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand, - (ClientData) cmdInfoPtr, format); - } - return TCL_OK; - } else if ((c == 'o') && (strncmp(argv[1], "own", length) == 0)) { - register LostCommand *lostPtr; - char *script = NULL; - int cmdLength; - - for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) { - if (args[0][0] != '-') { - break; - } - if (count < 2) { - Tcl_AppendResult(interp, "value for \"", *args, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - c = args[0][1]; - length = strlen(args[0]); - if ((c == 'c') && (strncmp(args[0], "-command", length) == 0)) { - script = args[1]; - } else if ((c == 'd') - && (strncmp(args[0], "-displayof", length) == 0)) { - path = args[1]; - } else if ((c == 's') - && (strncmp(args[0], "-selection", length) == 0)) { - selName = args[1]; - } else { - Tcl_AppendResult(interp, "unknown option \"", args[0], - "\"", (char *) NULL); - return TCL_ERROR; - } - } - - if (count > 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " own ?options? ?window?\"", (char *) NULL); - return TCL_ERROR; - } - if (selName != NULL) { - selection = Tk_InternAtom(tkwin, selName); - } else { - selection = XA_PRIMARY; - } - if (count == 0) { - TkSelectionInfo *infoPtr; - TkWindow *winPtr; - if (path != NULL) { - tkwin = Tk_NameToWindow(interp, path, tkwin); - } - if (tkwin == NULL) { - return TCL_ERROR; - } - winPtr = (TkWindow *)tkwin; - for (infoPtr = winPtr->dispPtr->selectionInfoPtr; infoPtr != NULL; - infoPtr = infoPtr->nextPtr) { - if (infoPtr->selection == selection) - break; - } - - /* - * Ignore the internal clipboard window. - */ - - if ((infoPtr != NULL) - && (infoPtr->owner != winPtr->dispPtr->clipWindow)) { - interp->result = Tk_PathName(infoPtr->owner); - } - return TCL_OK; - } - tkwin = Tk_NameToWindow(interp, args[0], tkwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - if (count == 2) { - script = args[1]; - } - if (script == NULL) { - Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL, - (ClientData) NULL); - return TCL_OK; - } - cmdLength = strlen(script); - lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand) - -3 + cmdLength)); - lostPtr->interp = interp; - strcpy(lostPtr->command, script); - Tk_OwnSelection(tkwin, selection, LostSelection, (ClientData) lostPtr); - return TCL_OK; - } else { - sprintf(interp->result, - "bad option \"%.50s\": must be clear, get, handle, or own", - argv[1]); - return TCL_ERROR; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkSelDeadWindow -- - * - * This procedure is invoked just before a TkWindow is deleted. - * It performs selection-related cleanup. - * - * Results: - * None. - * - * Side effects: - * Frees up memory associated with the selection. - * - *---------------------------------------------------------------------- - */ - -void -TkSelDeadWindow(winPtr) - register TkWindow *winPtr; /* Window that's being deleted. */ -{ - register TkSelHandler *selPtr; - register TkSelInProgress *ipPtr; - TkSelectionInfo *infoPtr, *prevPtr, *nextPtr; - - /* - * While deleting all the handlers, be careful to check whether - * ConvertSelection or TkSelPropProc are about to process one of the - * deleted handlers. - */ - - while (winPtr->selHandlerList != NULL) { - selPtr = winPtr->selHandlerList; - winPtr->selHandlerList = selPtr->nextPtr; - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { - if (ipPtr->selPtr == selPtr) { - ipPtr->selPtr = NULL; - } - } - if (selPtr->proc == HandleTclCommand) { - ckfree((char *) selPtr->clientData); - } - ckfree((char *) selPtr); - } - - /* - * Remove selections owned by window being deleted. - */ - - for (infoPtr = winPtr->dispPtr->selectionInfoPtr, prevPtr = NULL; - infoPtr != NULL; infoPtr = nextPtr) { - nextPtr = infoPtr->nextPtr; - if (infoPtr->owner == (Tk_Window) winPtr) { - if (infoPtr->clearProc == LostSelection) { - ckfree((char *) infoPtr->clearData); - } - ckfree((char *) infoPtr); - infoPtr = prevPtr; - if (prevPtr == NULL) { - winPtr->dispPtr->selectionInfoPtr = nextPtr; - } else { - prevPtr->nextPtr = nextPtr; - } - } - prevPtr = infoPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkSelInit -- - * - * Initialize selection-related information for a display. - * - * Results: - * None. - * - * Side effects: - * Selection-related information is initialized. - * - *---------------------------------------------------------------------- - */ - -void -TkSelInit(tkwin) - Tk_Window tkwin; /* Window token (used to find - * display to initialize). */ -{ - register TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - - /* - * Fetch commonly-used atoms. - */ - - dispPtr->multipleAtom = Tk_InternAtom(tkwin, "MULTIPLE"); - dispPtr->incrAtom = Tk_InternAtom(tkwin, "INCR"); - dispPtr->targetsAtom = Tk_InternAtom(tkwin, "TARGETS"); - dispPtr->timestampAtom = Tk_InternAtom(tkwin, "TIMESTAMP"); - dispPtr->textAtom = Tk_InternAtom(tkwin, "TEXT"); - dispPtr->compoundTextAtom = Tk_InternAtom(tkwin, "COMPOUND_TEXT"); - dispPtr->applicationAtom = Tk_InternAtom(tkwin, "TK_APPLICATION"); - dispPtr->windowAtom = Tk_InternAtom(tkwin, "TK_WINDOW"); - dispPtr->clipboardAtom = Tk_InternAtom(tkwin, "CLIPBOARD"); -} - -/* - *---------------------------------------------------------------------- - * - * TkSelClearSelection -- - * - * This procedure is invoked to process a SelectionClear event. - * - * Results: - * None. - * - * Side effects: - * Invokes the clear procedure for the window which lost the - * selection. - * - *---------------------------------------------------------------------- - */ - -void -TkSelClearSelection(tkwin, eventPtr) - Tk_Window tkwin; /* Window for which event was targeted. */ - register XEvent *eventPtr; /* X SelectionClear event. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - TkSelectionInfo *infoPtr; - TkSelectionInfo *prevPtr; - - /* - * Invoke clear procedure for window that just lost the selection. This - * code is a bit tricky, because any callbacks due to selection changes - * between windows managed by the process have already been made. Thus, - * ignore the event unless it refers to the window that's currently the - * selection owner and the event was generated after the server saw the - * SetSelectionOwner request. - */ - - for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL; - infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->selection == eventPtr->xselectionclear.selection) { - break; - } - prevPtr = infoPtr; - } - - if (infoPtr != NULL && (infoPtr->owner == tkwin) - && (eventPtr->xselectionclear.serial >= (unsigned) infoPtr->serial)) { - if (prevPtr == NULL) { - dispPtr->selectionInfoPtr = infoPtr->nextPtr; - } else { - prevPtr->nextPtr = infoPtr->nextPtr; - } - - /* - * Because of reentrancy problems, calling clearProc must be done - * after the infoPtr has been removed from the selectionInfoPtr - * list (clearProc could modify the list, e.g. by creating - * a new selection). - */ - - if (infoPtr->clearProc != NULL) { - (*infoPtr->clearProc)(infoPtr->clearData); - } - ckfree((char *) infoPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * SelGetProc -- - * - * This procedure is invoked to process pieces of the selection - * as they arrive during "selection get" commands. - * - * Results: - * Always returns TCL_OK. - * - * Side effects: - * Bytes get appended to the dynamic string pointed to by the - * clientData argument. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -SelGetProc(clientData, interp, portion) - ClientData clientData; /* Dynamic string holding partially - * assembled selection. */ - Tcl_Interp *interp; /* Interpreter used for error - * reporting (not used). */ - char *portion; /* New information to be appended. */ -{ - Tcl_DStringAppend((Tcl_DString *) clientData, portion, -1); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * HandleTclCommand -- - * - * This procedure acts as selection handler for handlers created - * by the "selection handle" command. It invokes a Tcl command to - * retrieve the selection. - * - * Results: - * The return value is a count of the number of bytes actually - * stored at buffer, or -1 if an error occurs while executing - * the Tcl command to retrieve the selection. - * - * Side effects: - * None except for things done by the Tcl command. - * - *---------------------------------------------------------------------- - */ - -static int -HandleTclCommand(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about command to execute. */ - int offset; /* Return selection bytes starting at this - * offset. */ - char *buffer; /* Place to store converted selection. */ - int maxBytes; /* Maximum # of bytes to store at buffer. */ -{ - CommandInfo *cmdInfoPtr = (CommandInfo *) clientData; - int spaceNeeded, length; -#define MAX_STATIC_SIZE 100 - char staticSpace[MAX_STATIC_SIZE]; - char *command; - Tcl_Interp *interp; - Tcl_DString oldResult; - - /* - * We must copy the interpreter pointer from CommandInfo because the - * command could delete the handler, freeing the CommandInfo data before we - * are done using it. We must also protect the interpreter from being - * deleted too soo. - */ - - interp = cmdInfoPtr->interp; - Tcl_Preserve((ClientData) interp); - - /* - * First, generate a command by taking the command string - * and appending the offset and maximum # of bytes. - */ - - spaceNeeded = cmdInfoPtr->cmdLength + 30; - if (spaceNeeded < MAX_STATIC_SIZE) { - command = staticSpace; - } else { - command = (char *) ckalloc((unsigned) spaceNeeded); - } - sprintf(command, "%s %d %d", cmdInfoPtr->command, offset, maxBytes); - - /* - * Execute the command. Be sure to restore the state of the - * interpreter after executing the command. - */ - - Tcl_DStringInit(&oldResult); - Tcl_DStringGetResult(interp, &oldResult); - if (TkCopyAndGlobalEval(interp, command) == TCL_OK) { - length = strlen(interp->result); - if (length > maxBytes) { - length = maxBytes; - } - memcpy((VOID *) buffer, (VOID *) interp->result, (size_t) length); - buffer[length] = '\0'; - } else { - length = -1; - } - Tcl_DStringResult(interp, &oldResult); - - if (command != staticSpace) { - ckfree(command); - } - - Tcl_Release((ClientData) interp); - return length; -} - -/* - *---------------------------------------------------------------------- - * - * TkSelDefaultSelection -- - * - * This procedure is called to generate selection information - * for a few standard targets such as TIMESTAMP and TARGETS. - * It is invoked only if no handler has been declared by the - * application. - * - * Results: - * If "target" is a standard target understood by this procedure, - * the selection is converted to that form and stored as a - * character string in buffer. The type of the selection (e.g. - * STRING or ATOM) is stored in *typePtr, and the return value is - * a count of the # of non-NULL bytes at buffer. If the target - * wasn't understood, or if there isn't enough space at buffer - * to hold the entire selection (no INCR-mode transfers for this - * stuff!), then -1 is returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr) - TkSelectionInfo *infoPtr; /* Info about selection being retrieved. */ - Atom target; /* Desired form of selection. */ - char *buffer; /* Place to put selection characters. */ - int maxBytes; /* Maximum # of bytes to store at buffer. */ - Atom *typePtr; /* Store here the type of the selection, - * for use in converting to proper X format. */ -{ - register TkWindow *winPtr = (TkWindow *) infoPtr->owner; - TkDisplay *dispPtr = winPtr->dispPtr; - - if (target == dispPtr->timestampAtom) { - if (maxBytes < 20) { - return -1; - } - sprintf(buffer, "0x%x", (unsigned int) infoPtr->time); - *typePtr = XA_INTEGER; - return strlen(buffer); - } - - if (target == dispPtr->targetsAtom) { - register TkSelHandler *selPtr; - char *atomString; - int length, atomLength; - - if (maxBytes < 50) { - return -1; - } - strcpy(buffer, "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW"); - length = strlen(buffer); - for (selPtr = winPtr->selHandlerList; selPtr != NULL; - selPtr = selPtr->nextPtr) { - if ((selPtr->selection == infoPtr->selection) - && (selPtr->target != dispPtr->applicationAtom) - && (selPtr->target != dispPtr->windowAtom)) { - atomString = Tk_GetAtomName((Tk_Window) winPtr, - selPtr->target); - atomLength = strlen(atomString) + 1; - if ((length + atomLength) >= maxBytes) { - return -1; - } - sprintf(buffer+length, " %s", atomString); - length += atomLength; - } - } - *typePtr = XA_ATOM; - return length; - } - - if (target == dispPtr->applicationAtom) { - int length; - char *name = winPtr->mainPtr->winPtr->nameUid; - - length = strlen(name); - if (maxBytes <= length) { - return -1; - } - strcpy(buffer, name); - *typePtr = XA_STRING; - return length; - } - - if (target == dispPtr->windowAtom) { - int length; - char *name = winPtr->pathName; - - length = strlen(name); - if (maxBytes <= length) { - return -1; - } - strcpy(buffer, name); - *typePtr = XA_STRING; - return length; - } - - return -1; -} - -/* - *---------------------------------------------------------------------- - * - * LostSelection -- - * - * This procedure is invoked when a window has lost ownership of - * the selection and the ownership was claimed with the command - * "selection own". - * - * Results: - * None. - * - * Side effects: - * A Tcl script is executed; it can do almost anything. - * - *---------------------------------------------------------------------- - */ - -static void -LostSelection(clientData) - ClientData clientData; /* Pointer to CommandInfo structure. */ -{ - LostCommand *lostPtr = (LostCommand *) clientData; - char *oldResultString; - Tcl_FreeProc *oldFreeProc; - Tcl_Interp *interp; - - interp = lostPtr->interp; - Tcl_Preserve((ClientData) interp); - - /* - * Execute the command. Save the interpreter's result, if any, and - * restore it after executing the command. - */ - - oldFreeProc = interp->freeProc; - if (oldFreeProc != TCL_STATIC) { - oldResultString = interp->result; - } else { - oldResultString = (char *) ckalloc((unsigned) - (strlen(interp->result) + 1)); - strcpy(oldResultString, interp->result); - oldFreeProc = TCL_DYNAMIC; - } - interp->freeProc = TCL_STATIC; - if (TkCopyAndGlobalEval(interp, lostPtr->command) != TCL_OK) { - Tcl_BackgroundError(interp); - } - Tcl_FreeResult(interp); - interp->result = oldResultString; - interp->freeProc = oldFreeProc; - - Tcl_Release((ClientData) interp); - - /* - * Free the storage for the command, since we're done with it now. - */ - - ckfree((char *) lostPtr); -} diff --git a/generic/tkSelect.h b/generic/tkSelect.h deleted file mode 100644 index 4963f71..0000000 --- a/generic/tkSelect.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * tkSelect.h -- - * - * Declarations of types shared among the files that implement - * selection support. - * - * Copyright (c) 1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkSelect.h,v 1.2 1998/09/14 18:23:17 stanton Exp $ - */ - -#ifndef _TKSELECT -#define _TKSELECT - -/* - * When a selection is owned by a window on a given display, one of the - * following structures is present on a list of current selections in the - * display structure. The structure is used to record the current owner of - * a selection for use in later retrieval requests. There is a list of - * such structures because a display can have multiple different selections - * active at the same time. - */ - -typedef struct TkSelectionInfo { - Atom selection; /* Selection name, e.g. XA_PRIMARY. */ - Tk_Window owner; /* Current owner of this selection. */ - int serial; /* Serial number of last XSelectionSetOwner - * request made to server for this - * selection (used to filter out redundant - * SelectionClear events). */ - Time time; /* Timestamp used to acquire selection. */ - Tk_LostSelProc *clearProc; /* Procedure to call when owner loses - * selection. */ - ClientData clearData; /* Info to pass to clearProc. */ - struct TkSelectionInfo *nextPtr; - /* Next in list of current selections on - * this display. NULL means end of list */ -} TkSelectionInfo; - -/* - * One of the following structures exists for each selection handler - * created for a window by calling Tk_CreateSelHandler. The handlers - * are linked in a list rooted in the TkWindow structure. - */ - -typedef struct TkSelHandler { - Atom selection; /* Selection name, e.g. XA_PRIMARY */ - Atom target; /* Target type for selection - * conversion, such as TARGETS or - * STRING. */ - Atom format; /* Format in which selection - * info will be returned, such - * as STRING or ATOM. */ - Tk_SelectionProc *proc; /* Procedure to generate selection - * in this format. */ - ClientData clientData; /* Argument to pass to proc. */ - int size; /* Size of units returned by proc - * (8 for STRING, 32 for almost - * anything else). */ - struct TkSelHandler *nextPtr; - /* Next selection handler associated - * with same window (NULL for end of - * list). */ -} TkSelHandler; - -/* - * When the selection is being retrieved, one of the following - * structures is present on a list of pending selection retrievals. - * The structure is used to communicate between the background - * procedure that requests the selection and the foreground - * event handler that processes the events in which the selection - * is returned. There is a list of such structures so that there - * can be multiple simultaneous selection retrievals (e.g. on - * different displays). - */ - -typedef struct TkSelRetrievalInfo { - Tcl_Interp *interp; /* Interpreter for error reporting. */ - TkWindow *winPtr; /* Window used as requestor for - * selection. */ - Atom selection; /* Selection being requested. */ - Atom property; /* Property where selection will appear. */ - Atom target; /* Desired form for selection. */ - int (*proc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, - char *portion)); /* Procedure to call to handle pieces - * of selection. */ - ClientData clientData; /* Argument for proc. */ - int result; /* Initially -1. Set to a Tcl - * return value once the selection - * has been retrieved. */ - Tcl_TimerToken timeout; /* Token for current timeout procedure. */ - int idleTime; /* Number of seconds that have gone by - * without hearing anything from the - * selection owner. */ - struct TkSelRetrievalInfo *nextPtr; - /* Next in list of all pending - * selection retrievals. NULL means - * end of list. */ -} TkSelRetrievalInfo; - -/* - * The clipboard contains a list of buffers of various types and formats. - * All of the buffers of a given type will be returned in sequence when the - * CLIPBOARD selection is retrieved. All buffers of a given type on the - * same clipboard must have the same format. The TkClipboardTarget structure - * is used to record the information about a chain of buffers of the same - * type. - */ - -typedef struct TkClipboardBuffer { - char *buffer; /* Null terminated data buffer. */ - long length; /* Length of string in buffer. */ - struct TkClipboardBuffer *nextPtr; /* Next in list of buffers. NULL - * means end of list . */ -} TkClipboardBuffer; - -typedef struct TkClipboardTarget { - Atom type; /* Type conversion supported. */ - Atom format; /* Representation used for data. */ - TkClipboardBuffer *firstBufferPtr; /* First in list of data buffers. */ - TkClipboardBuffer *lastBufferPtr; /* Last in list of clipboard buffers. - * Used to speed up appends. */ - struct TkClipboardTarget *nextPtr; /* Next in list of targets on - * clipboard. NULL means end of - * list. */ -} TkClipboardTarget; - -/* - * It is possible for a Tk_SelectionProc to delete the handler that it - * represents. If this happens, the code that is retrieving the selection - * needs to know about it so it doesn't use the now-defunct handler - * structure. One structure of the following form is created for each - * retrieval in progress, so that the retriever can find out if its - * handler is deleted. All of the pending retrievals (if there are more - * than one) are linked into a list. - */ - -typedef struct TkSelInProgress { - TkSelHandler *selPtr; /* Handler being executed. If this handler - * is deleted, the field is set to NULL. */ - struct TkSelInProgress *nextPtr; - /* Next higher nested search. */ -} TkSelInProgress; - -/* - * Declarations for variables shared among the selection-related files: - */ - -extern TkSelInProgress *pendingPtr; - /* Topmost search in progress, or - * NULL if none. */ - -/* - * Chunk size for retrieving selection. It's defined both in - * words and in bytes; the word size is used to allocate - * buffer space that's guaranteed to be word-aligned and that - * has an extra character for the terminating NULL. - */ - -#define TK_SEL_BYTES_AT_ONCE 4000 -#define TK_SEL_WORDS_AT_ONCE 1001 - -/* - * Declarations for procedures that are used by the selection-related files - * but shouldn't be used anywhere else in Tk (or by Tk clients): - */ - -extern void TkSelClearSelection _ANSI_ARGS_((Tk_Window tkwin, - XEvent *eventPtr)); -extern int TkSelDefaultSelection _ANSI_ARGS_(( - TkSelectionInfo *infoPtr, Atom target, - char *buffer, int maxBytes, Atom *typePtr)); -extern int TkSelGetSelection _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Atom selection, Atom target, - Tk_GetSelProc *proc, ClientData clientData)); -#ifndef TkSelUpdateClipboard -extern void TkSelUpdateClipboard _ANSI_ARGS_((TkWindow *winPtr, - TkClipboardTarget *targetPtr)); -#endif - -#endif /* _TKSELECT */ diff --git a/generic/tkSquare.c b/generic/tkSquare.c deleted file mode 100644 index e7cc047..0000000 --- a/generic/tkSquare.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * tkSquare.c -- - * - * This module implements "square" widgets. A "square" is - * a widget that displays a single square that can be moved - * around and resized. This file is intended as an example - * of how to build a widget; it isn't included in the - * normal wish, but it is included in "tktest". - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkSquare.c,v 1.2 1998/09/14 18:23:17 stanton Exp $ - */ - -#include "tkPort.h" -#include "tk.h" - -/* - * A data structure of the following type is kept for each square - * widget managed by this file: - */ - -typedef struct { - Tk_Window tkwin; /* Window that embodies the square. NULL - * means window has been deleted but - * widget record hasn't been cleaned up yet. */ - Display *display; /* X's token for the window's display. */ - Tcl_Interp *interp; /* Interpreter associated with widget. */ - Tcl_Command widgetCmd; /* Token for square's widget command. */ - int x, y; /* Position of square's upper-left corner - * within widget. */ - int size; /* Width and height of square. */ - - /* - * Information used when displaying widget: - */ - - int borderWidth; /* Width of 3-D border around whole widget. */ - Tk_3DBorder bgBorder; /* Used for drawing background. */ - Tk_3DBorder fgBorder; /* For drawing square. */ - int relief; /* Indicates whether window as a whole is - * raised, sunken, or flat. */ - GC gc; /* Graphics context for copying from - * off-screen pixmap onto screen. */ - int doubleBuffer; /* Non-zero means double-buffer redisplay - * with pixmap; zero means draw straight - * onto the display. */ - int updatePending; /* Non-zero means a call to SquareDisplay - * has already been scheduled. */ -} Square; - -/* - * Information used for argv parsing. - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - "#d9d9d9", Tk_Offset(Square, bgBorder), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - "white", Tk_Offset(Square, bgBorder), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - "2", Tk_Offset(Square, borderWidth), 0}, - {TK_CONFIG_INT, "-dbl", "doubleBuffer", "DoubleBuffer", - "1", Tk_Offset(Square, doubleBuffer), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", - "#b03060", Tk_Offset(Square, fgBorder), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", - "black", Tk_Offset(Square, fgBorder), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - "raised", Tk_Offset(Square, relief), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -int SquareCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void SquareCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static int SquareConfigure _ANSI_ARGS_((Tcl_Interp *interp, - Square *squarePtr, int argc, char **argv, - int flags)); -static void SquareDestroy _ANSI_ARGS_((char *memPtr)); -static void SquareDisplay _ANSI_ARGS_((ClientData clientData)); -static void KeepInWindow _ANSI_ARGS_((Square *squarePtr)); -static void SquareEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int SquareWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *, int argc, char **argv)); - -/* - *-------------------------------------------------------------- - * - * SquareCmd -- - * - * This procedure is invoked to process the "square" Tcl - * command. It creates a new "square" widget. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * A new widget is created and configured. - * - *-------------------------------------------------------------- - */ - -int -SquareCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window main = (Tk_Window) clientData; - Square *squarePtr; - Tk_Window tkwin; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL); - if (tkwin == NULL) { - return TCL_ERROR; - } - Tk_SetClass(tkwin, "Square"); - - /* - * Allocate and initialize the widget record. - */ - - squarePtr = (Square *) ckalloc(sizeof(Square)); - squarePtr->tkwin = tkwin; - squarePtr->display = Tk_Display(tkwin); - squarePtr->interp = interp; - squarePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(squarePtr->tkwin), SquareWidgetCmd, - (ClientData) squarePtr, SquareCmdDeletedProc); - squarePtr->x = 0; - squarePtr->y = 0; - squarePtr->size = 20; - squarePtr->borderWidth = 0; - squarePtr->bgBorder = NULL; - squarePtr->fgBorder = NULL; - squarePtr->relief = TK_RELIEF_FLAT; - squarePtr->gc = None; - squarePtr->doubleBuffer = 1; - squarePtr->updatePending = 0; - - Tk_CreateEventHandler(squarePtr->tkwin, ExposureMask|StructureNotifyMask, - SquareEventProc, (ClientData) squarePtr); - if (SquareConfigure(interp, squarePtr, argc-2, argv+2, 0) != TCL_OK) { - Tk_DestroyWindow(squarePtr->tkwin); - return TCL_ERROR; - } - - interp->result = Tk_PathName(squarePtr->tkwin); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * SquareWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -SquareWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about square widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Square *squarePtr = (Square *) clientData; - int result = TCL_OK; - size_t length; - char c; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) squarePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, argv[2], 0); - } else { - result = SquareConfigure(interp, squarePtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'p') && (strncmp(argv[1], "position", length) == 0)) { - if ((argc != 2) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " position ?x y?\"", (char *) NULL); - goto error; - } - if (argc == 4) { - if ((Tk_GetPixels(interp, squarePtr->tkwin, argv[2], - &squarePtr->x) != TCL_OK) || (Tk_GetPixels(interp, - squarePtr->tkwin, argv[3], &squarePtr->y) != TCL_OK)) { - goto error; - } - KeepInWindow(squarePtr); - } - sprintf(interp->result, "%d %d", squarePtr->x, squarePtr->y); - } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)) { - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " size ?amount?\"", (char *) NULL); - goto error; - } - if (argc == 3) { - int i; - - if (Tk_GetPixels(interp, squarePtr->tkwin, argv[2], &i) != TCL_OK) { - goto error; - } - if ((i <= 0) || (i > 100)) { - Tcl_AppendResult(interp, "bad size \"", argv[2], - "\"", (char *) NULL); - goto error; - } - squarePtr->size = i; - KeepInWindow(squarePtr); - } - sprintf(interp->result, "%d", squarePtr->size); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget, configure, position, or size", - (char *) NULL); - goto error; - } - if (!squarePtr->updatePending) { - Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); - squarePtr->updatePending = 1; - } - Tcl_Release((ClientData) squarePtr); - return result; - - error: - Tcl_Release((ClientData) squarePtr); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * SquareConfigure -- - * - * This procedure is called to process an argv/argc list in - * conjunction with the Tk option database to configure (or - * reconfigure) a square widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as colors, border width, - * etc. get set for squarePtr; old resources get freed, - * if there were any. - * - *---------------------------------------------------------------------- - */ - -static int -SquareConfigure(interp, squarePtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - Square *squarePtr; /* Information about widget. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to - * Tk_ConfigureWidget. */ -{ - if (Tk_ConfigureWidget(interp, squarePtr->tkwin, configSpecs, - argc, argv, (char *) squarePtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Set the background for the window and create a graphics context - * for use during redisplay. - */ - - Tk_SetWindowBackground(squarePtr->tkwin, - Tk_3DBorderColor(squarePtr->bgBorder)->pixel); - if ((squarePtr->gc == None) && (squarePtr->doubleBuffer)) { - XGCValues gcValues; - gcValues.function = GXcopy; - gcValues.graphics_exposures = False; - squarePtr->gc = Tk_GetGC(squarePtr->tkwin, - GCFunction|GCGraphicsExposures, &gcValues); - } - - /* - * Register the desired geometry for the window. Then arrange for - * the window to be redisplayed. - */ - - Tk_GeometryRequest(squarePtr->tkwin, 200, 150); - Tk_SetInternalBorder(squarePtr->tkwin, squarePtr->borderWidth); - if (!squarePtr->updatePending) { - Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); - squarePtr->updatePending = 1; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * SquareEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various - * events on squares. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -SquareEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - XEvent *eventPtr; /* Information about event. */ -{ - Square *squarePtr = (Square *) clientData; - - if (eventPtr->type == Expose) { - if (!squarePtr->updatePending) { - Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); - squarePtr->updatePending = 1; - } - } else if (eventPtr->type == ConfigureNotify) { - KeepInWindow(squarePtr); - if (!squarePtr->updatePending) { - Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); - squarePtr->updatePending = 1; - } - } else if (eventPtr->type == DestroyNotify) { - if (squarePtr->tkwin != NULL) { - squarePtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(squarePtr->interp, - squarePtr->widgetCmd); - } - if (squarePtr->updatePending) { - Tcl_CancelIdleCall(SquareDisplay, (ClientData) squarePtr); - } - Tcl_EventuallyFree((ClientData) squarePtr, SquareDestroy); - } -} - -/* - *---------------------------------------------------------------------- - * - * SquareCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -SquareCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - Square *squarePtr = (Square *) clientData; - Tk_Window tkwin = squarePtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - squarePtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *-------------------------------------------------------------- - * - * SquareDisplay -- - * - * This procedure redraws the contents of a square window. - * It is invoked as a do-when-idle handler, so it only runs - * when there's nothing else for the application to do. - * - * Results: - * None. - * - * Side effects: - * Information appears on the screen. - * - *-------------------------------------------------------------- - */ - -static void -SquareDisplay(clientData) - ClientData clientData; /* Information about window. */ -{ - Square *squarePtr = (Square *) clientData; - Tk_Window tkwin = squarePtr->tkwin; - Pixmap pm = None; - Drawable d; - - squarePtr->updatePending = 0; - if (!Tk_IsMapped(tkwin)) { - return; - } - - /* - * Create a pixmap for double-buffering, if necessary. - */ - - if (squarePtr->doubleBuffer) { - pm = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), - DefaultDepthOfScreen(Tk_Screen(tkwin))); - d = pm; - } else { - d = Tk_WindowId(tkwin); - } - - /* - * Redraw the widget's background and border. - */ - - Tk_Fill3DRectangle(tkwin, d, squarePtr->bgBorder, 0, 0, Tk_Width(tkwin), - Tk_Height(tkwin), squarePtr->borderWidth, squarePtr->relief); - - /* - * Display the square. - */ - - Tk_Fill3DRectangle(tkwin, d, squarePtr->fgBorder, squarePtr->x, - squarePtr->y, squarePtr->size, squarePtr->size, - squarePtr->borderWidth, TK_RELIEF_RAISED); - - /* - * If double-buffered, copy to the screen and release the pixmap. - */ - - if (squarePtr->doubleBuffer) { - XCopyArea(Tk_Display(tkwin), pm, Tk_WindowId(tkwin), squarePtr->gc, - 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), - 0, 0); - Tk_FreePixmap(Tk_Display(tkwin), pm); - } -} - -/* - *---------------------------------------------------------------------- - * - * SquareDestroy -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a square at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the square is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -SquareDestroy(memPtr) - char *memPtr; /* Info about square widget. */ -{ - Square *squarePtr = (Square *) memPtr; - - Tk_FreeOptions(configSpecs, (char *) squarePtr, squarePtr->display, 0); - if (squarePtr->gc != None) { - Tk_FreeGC(squarePtr->display, squarePtr->gc); - } - ckfree((char *) squarePtr); -} - -/* - *---------------------------------------------------------------------- - * - * KeepInWindow -- - * - * Adjust the position of the square if necessary to keep it in - * the widget's window. - * - * Results: - * None. - * - * Side effects: - * The x and y position of the square are adjusted if necessary - * to keep the square in the window. - * - *---------------------------------------------------------------------- - */ - -static void -KeepInWindow(squarePtr) - register Square *squarePtr; /* Pointer to widget record. */ -{ - int i, bd; - bd = 0; - if (squarePtr->relief != TK_RELIEF_FLAT) { - bd = squarePtr->borderWidth; - } - i = (Tk_Width(squarePtr->tkwin) - bd) - (squarePtr->x + squarePtr->size); - if (i < 0) { - squarePtr->x += i; - } - i = (Tk_Height(squarePtr->tkwin) - bd) - (squarePtr->y + squarePtr->size); - if (i < 0) { - squarePtr->y += i; - } - if (squarePtr->x < bd) { - squarePtr->x = bd; - } - if (squarePtr->y < bd) { - squarePtr->y = bd; - } -} diff --git a/generic/tkTest.c b/generic/tkTest.c deleted file mode 100644 index e5de871..0000000 --- a/generic/tkTest.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * tkTest.c -- - * - * This file contains C command procedures for a bunch of additional - * Tcl commands that are used for testing out Tcl's C interfaces. - * These commands are not normally included in Tcl applications; - * they're only used for testing. - * - * Copyright (c) 1993-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTest.c,v 1.3 1998/09/14 18:23:17 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -#ifdef __WIN32__ -#include "tkWinInt.h" -#endif - -#ifdef MAC_TCL -#include "tkScrollbar.h" -#endif - -#ifdef __UNIX__ -#include "tkUnixInt.h" -#endif - -/* - * The following data structure represents the master for a test - * image: - */ - -typedef struct TImageMaster { - Tk_ImageMaster master; /* Tk's token for image master. */ - Tcl_Interp *interp; /* Interpreter for application. */ - int width, height; /* Dimensions of image. */ - char *imageName; /* Name of image (malloc-ed). */ - char *varName; /* Name of variable in which to log - * events for image (malloc-ed). */ -} TImageMaster; - -/* - * The following data structure represents a particular use of a - * particular test image. - */ - -typedef struct TImageInstance { - TImageMaster *masterPtr; /* Pointer to master for image. */ - XColor *fg; /* Foreground color for drawing in image. */ - GC gc; /* Graphics context for drawing in image. */ -} TImageInstance; - -/* - * The type record for test images: - */ - -static int ImageCreate _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int argc, char **argv, - Tk_ImageType *typePtr, Tk_ImageMaster master, - ClientData *clientDataPtr)); -static ClientData ImageGet _ANSI_ARGS_((Tk_Window tkwin, - ClientData clientData)); -static void ImageDisplay _ANSI_ARGS_((ClientData clientData, - Display *display, Drawable drawable, - int imageX, int imageY, int width, - int height, int drawableX, - int drawableY)); -static void ImageFree _ANSI_ARGS_((ClientData clientData, - Display *display)); -static void ImageDelete _ANSI_ARGS_((ClientData clientData)); - -static Tk_ImageType imageType = { - "test", /* name */ - ImageCreate, /* createProc */ - ImageGet, /* getProc */ - ImageDisplay, /* displayProc */ - ImageFree, /* freeProc */ - ImageDelete, /* deleteProc */ - (Tk_ImageType *) NULL /* nextPtr */ -}; - -/* - * One of the following structures describes each of the interpreters - * created by the "testnewapp" command. This information is used by - * the "testdeleteinterps" command to destroy all of those interpreters. - */ - -typedef struct NewApp { - Tcl_Interp *interp; /* Token for interpreter. */ - struct NewApp *nextPtr; /* Next in list of new interpreters. */ -} NewApp; - -static NewApp *newAppPtr = NULL; - /* First in list of all new interpreters. */ - -/* - * Declaration for the square widget's class command procedure: - */ - -extern int SquareCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char *argv[])); - -typedef struct CBinding { - Tcl_Interp *interp; - char *command; - char *delete; -} CBinding; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int CBindingEvalProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, XEvent *eventPtr, - Tk_Window tkwin, KeySym keySym)); -static void CBindingFreeProc _ANSI_ARGS_((ClientData clientData)); -int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -static int ImageCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -static int TestcbindCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#ifdef __WIN32__ -static int TestclipboardCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#endif -static int TestdeleteappsCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -static int TestmakeexistCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -static int TestmenubarCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#if defined(__WIN32__) || defined(MAC_TCL) -static int TestmetricsCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#endif -static int TestsendCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -static int TestpropCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#if !(defined(__WIN32__) || defined(MAC_TCL)) -static int TestwrapperCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#endif - -/* - * External (platform specific) initialization routine: - */ - -EXTERN int TkplatformtestInit _ANSI_ARGS_(( - Tcl_Interp *interp)); -#ifndef MAC_TCL -#define TkplatformtestInit(x) TCL_OK -#endif - -/* - *---------------------------------------------------------------------- - * - * Tktest_Init -- - * - * This procedure performs intialization for the Tk test - * suite exensions. - * - * Results: - * Returns a standard Tcl completion code, and leaves an error - * message in interp->result if an error occurs. - * - * Side effects: - * Creates several test commands. - * - *---------------------------------------------------------------------- - */ - -int -Tktest_Init(interp) - Tcl_Interp *interp; /* Interpreter for application. */ -{ - static int initialized = 0; - - /* - * Create additional commands for testing Tk. - */ - - if (Tcl_PkgProvide(interp, "Tktest", TK_VERSION) == TCL_ERROR) { - return TCL_ERROR; - } - - Tcl_CreateCommand(interp, "square", SquareCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#ifdef __WIN32__ - Tcl_CreateCommand(interp, "testclipboard", TestclipboardCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#endif - Tcl_CreateCommand(interp, "testcbind", TestcbindCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testdeleteapps", TestdeleteappsCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testembed", TkpTestembedCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testmakeexist", TestmakeexistCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testmenubar", TestmenubarCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#if defined(__WIN32__) || defined(MAC_TCL) - Tcl_CreateCommand(interp, "testmetrics", TestmetricsCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#endif - Tcl_CreateCommand(interp, "testprop", TestpropCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testsend", TestsendCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#if !(defined(__WIN32__) || defined(MAC_TCL)) - Tcl_CreateCommand(interp, "testwrapper", TestwrapperCmd, - (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#endif - -/* - * Create test image type. - */ - - if (!initialized) { - initialized = 1; - Tk_CreateImageType(&imageType); - } - - /* - * And finally add any platform specific test commands. - */ - - return TkplatformtestInit(interp); -} - -/* - *---------------------------------------------------------------------- - * - * TestclipboardCmd -- - * - * This procedure implements the testclipboard command. It provides - * a way to determine the actual contents of the Windows clipboard. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#ifdef __WIN32__ -static int -TestclipboardCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr = (TkWindow *) clientData; - HGLOBAL handle; - char *data; - - if (OpenClipboard(NULL)) { - handle = GetClipboardData(CF_TEXT); - if (handle != NULL) { - data = GlobalLock(handle); - Tcl_AppendResult(interp, data, (char *) NULL); - GlobalUnlock(handle); - } - CloseClipboard(); - } - return TCL_OK; -} -#endif - -/* - *---------------------------------------------------------------------- - * - * TestcbindCmd -- - * - * This procedure implements the "testcbinding" command. It provides - * a set of functions for testing C bindings in tkBind.c. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Depends on option; see below. - * - *---------------------------------------------------------------------- - */ - -static int -TestcbindCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr; - Tk_Window tkwin; - ClientData object; - CBinding *cbindPtr; - - - if (argc < 4 || argc > 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " bindtag pattern command ?deletecommand?", (char *) NULL); - return TCL_ERROR; - } - - tkwin = (Tk_Window) clientData; - - if (argv[1][0] == '.') { - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); - if (winPtr == NULL) { - return TCL_ERROR; - } - object = (ClientData) winPtr->pathName; - } else { - winPtr = (TkWindow *) clientData; - object = (ClientData) Tk_GetUid(argv[1]); - } - - if (argv[3][0] == '\0') { - return Tk_DeleteBinding(interp, winPtr->mainPtr->bindingTable, - object, argv[2]); - } - - cbindPtr = (CBinding *) ckalloc(sizeof(CBinding)); - cbindPtr->interp = interp; - cbindPtr->command = - strcpy((char *) ckalloc(strlen(argv[3]) + 1), argv[3]); - if (argc == 4) { - cbindPtr->delete = NULL; - } else { - cbindPtr->delete = - strcpy((char *) ckalloc(strlen(argv[4]) + 1), argv[4]); - } - - if (TkCreateBindingProcedure(interp, winPtr->mainPtr->bindingTable, - object, argv[2], CBindingEvalProc, CBindingFreeProc, - (ClientData) cbindPtr) == 0) { - ckfree((char *) cbindPtr->command); - if (cbindPtr->delete != NULL) { - ckfree((char *) cbindPtr->delete); - } - ckfree((char *) cbindPtr); - return TCL_ERROR; - } - return TCL_OK; -} - -static int -CBindingEvalProc(clientData, interp, eventPtr, tkwin, keySym) - ClientData clientData; - Tcl_Interp *interp; - XEvent *eventPtr; - Tk_Window tkwin; - KeySym keySym; -{ - CBinding *cbindPtr; - - cbindPtr = (CBinding *) clientData; - - return Tcl_GlobalEval(interp, cbindPtr->command); -} - -static void -CBindingFreeProc(clientData) - ClientData clientData; -{ - CBinding *cbindPtr = (CBinding *) clientData; - - if (cbindPtr->delete != NULL) { - Tcl_GlobalEval(cbindPtr->interp, cbindPtr->delete); - ckfree((char *) cbindPtr->delete); - } - ckfree((char *) cbindPtr->command); - ckfree((char *) cbindPtr); -} - -/* - *---------------------------------------------------------------------- - * - * TestdeleteappsCmd -- - * - * This procedure implements the "testdeleteapps" command. It cleans - * up all the interpreters left behind by the "testnewapp" command. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * All the intepreters created by previous calls to "testnewapp" - * get deleted. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestdeleteappsCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - NewApp *nextPtr; - - while (newAppPtr != NULL) { - nextPtr = newAppPtr->nextPtr; - Tcl_DeleteInterp(newAppPtr->interp); - ckfree((char *) newAppPtr); - newAppPtr = nextPtr; - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImageCreate -- - * - * This procedure is called by the Tk image code to create "test" - * images. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * The data structure for a new image is allocated. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ImageCreate(interp, name, argc, argv, typePtr, master, clientDataPtr) - Tcl_Interp *interp; /* Interpreter for application containing - * image. */ - char *name; /* Name to use for image. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings for options (doesn't - * include image name or type). */ - Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ - Tk_ImageMaster master; /* Token for image, to be used by us in - * later callbacks. */ - ClientData *clientDataPtr; /* Store manager's token for image here; - * it will be returned in later callbacks. */ -{ - TImageMaster *timPtr; - char *varName; - int i; - - varName = "log"; - for (i = 0; i < argc; i += 2) { - if (strcmp(argv[i], "-variable") != 0) { - Tcl_AppendResult(interp, "bad option name \"", argv[i], - "\"", (char *) NULL); - return TCL_ERROR; - } - if ((i+1) == argc) { - Tcl_AppendResult(interp, "no value given for \"", argv[i], - "\" option", (char *) NULL); - return TCL_ERROR; - } - varName = argv[i+1]; - } - timPtr = (TImageMaster *) ckalloc(sizeof(TImageMaster)); - timPtr->master = master; - timPtr->interp = interp; - timPtr->width = 30; - timPtr->height = 15; - timPtr->imageName = (char *) ckalloc((unsigned) (strlen(name) + 1)); - strcpy(timPtr->imageName, name); - timPtr->varName = (char *) ckalloc((unsigned) (strlen(varName) + 1)); - strcpy(timPtr->varName, varName); - Tcl_CreateCommand(interp, name, ImageCmd, (ClientData) timPtr, - (Tcl_CmdDeleteProc *) NULL); - *clientDataPtr = (ClientData) timPtr; - Tk_ImageChanged(master, 0, 0, 30, 15, 30, 15); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImageCmd -- - * - * This procedure implements the commands corresponding to individual - * images. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Forces windows to be created. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -ImageCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TImageMaster *timPtr = (TImageMaster *) clientData; - int x, y, width, height; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], "option ?arg arg ...?", (char *) NULL); - return TCL_ERROR; - } - if (strcmp(argv[1], "changed") == 0) { - if (argc != 8) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " changed x y width height imageWidth imageHeight", - (char *) NULL); - return TCL_ERROR; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &width) != TCL_OK) - || (Tcl_GetInt(interp, argv[5], &height) != TCL_OK) - || (Tcl_GetInt(interp, argv[6], &timPtr->width) != TCL_OK) - || (Tcl_GetInt(interp, argv[7], &timPtr->height) != TCL_OK)) { - return TCL_ERROR; - } - Tk_ImageChanged(timPtr->master, x, y, width, height, timPtr->width, - timPtr->height); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be changed", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ImageGet -- - * - * This procedure is called by Tk to set things up for using a - * test image in a particular widget. - * - * Results: - * The return value is a token for the image instance, which is - * used in future callbacks to ImageDisplay and ImageFree. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static ClientData -ImageGet(tkwin, clientData) - Tk_Window tkwin; /* Token for window in which image will - * be used. */ - ClientData clientData; /* Pointer to TImageMaster for image. */ -{ - TImageMaster *timPtr = (TImageMaster *) clientData; - TImageInstance *instPtr; - char buffer[100]; - XGCValues gcValues; - - sprintf(buffer, "%s get", timPtr->imageName); - Tcl_SetVar(timPtr->interp, timPtr->varName, buffer, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - - instPtr = (TImageInstance *) ckalloc(sizeof(TImageInstance)); - instPtr->masterPtr = timPtr; - instPtr->fg = Tk_GetColor(timPtr->interp, tkwin, "#ff0000"); - gcValues.foreground = instPtr->fg->pixel; - instPtr->gc = Tk_GetGC(tkwin, GCForeground, &gcValues); - return (ClientData) instPtr; -} - -/* - *---------------------------------------------------------------------- - * - * ImageDisplay -- - * - * This procedure is invoked to redisplay part or all of an - * image in a given drawable. - * - * Results: - * None. - * - * Side effects: - * The image gets partially redrawn, as an "X" that shows the - * exact redraw area. - * - *---------------------------------------------------------------------- - */ - -static void -ImageDisplay(clientData, display, drawable, imageX, imageY, width, height, - drawableX, drawableY) - ClientData clientData; /* Pointer to TImageInstance for image. */ - Display *display; /* Display to use for drawing. */ - Drawable drawable; /* Where to redraw image. */ - int imageX, imageY; /* Origin of area to redraw, relative to - * origin of image. */ - int width, height; /* Dimensions of area to redraw. */ - int drawableX, drawableY; /* Coordinates in drawable corresponding to - * imageX and imageY. */ -{ - TImageInstance *instPtr = (TImageInstance *) clientData; - char buffer[200]; - - sprintf(buffer, "%s display %d %d %d %d %d %d", - instPtr->masterPtr->imageName, imageX, imageY, width, height, - drawableX, drawableY); - Tcl_SetVar(instPtr->masterPtr->interp, instPtr->masterPtr->varName, buffer, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - if (width > (instPtr->masterPtr->width - imageX)) { - width = instPtr->masterPtr->width - imageX; - } - if (height > (instPtr->masterPtr->height - imageY)) { - height = instPtr->masterPtr->height - imageY; - } - XDrawRectangle(display, drawable, instPtr->gc, drawableX, drawableY, - (unsigned) (width-1), (unsigned) (height-1)); - XDrawLine(display, drawable, instPtr->gc, drawableX, drawableY, - (int) (drawableX + width - 1), (int) (drawableY + height - 1)); - XDrawLine(display, drawable, instPtr->gc, drawableX, - (int) (drawableY + height - 1), - (int) (drawableX + width - 1), drawableY); -} - -/* - *---------------------------------------------------------------------- - * - * ImageFree -- - * - * This procedure is called when an instance of an image is - * no longer used. - * - * Results: - * None. - * - * Side effects: - * Information related to the instance is freed. - * - *---------------------------------------------------------------------- - */ - -static void -ImageFree(clientData, display) - ClientData clientData; /* Pointer to TImageInstance for instance. */ - Display *display; /* Display where image was to be drawn. */ -{ - TImageInstance *instPtr = (TImageInstance *) clientData; - char buffer[200]; - - sprintf(buffer, "%s free", instPtr->masterPtr->imageName); - Tcl_SetVar(instPtr->masterPtr->interp, instPtr->masterPtr->varName, buffer, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - Tk_FreeColor(instPtr->fg); - Tk_FreeGC(display, instPtr->gc); - ckfree((char *) instPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ImageDelete -- - * - * This procedure is called to clean up a test image when - * an application goes away. - * - * Results: - * None. - * - * Side effects: - * Information about the image is deleted. - * - *---------------------------------------------------------------------- - */ - -static void -ImageDelete(clientData) - ClientData clientData; /* Pointer to TImageMaster for image. When - * this procedure is called, no more - * instances exist. */ -{ - TImageMaster *timPtr = (TImageMaster *) clientData; - char buffer[100]; - - sprintf(buffer, "%s delete", timPtr->imageName); - Tcl_SetVar(timPtr->interp, timPtr->varName, buffer, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - - Tcl_DeleteCommand(timPtr->interp, timPtr->imageName); - ckfree(timPtr->imageName); - ckfree(timPtr->varName); - ckfree((char *) timPtr); -} - -/* - *---------------------------------------------------------------------- - * - * TestmakeexistCmd -- - * - * This procedure implements the "testmakeexist" command. It calls - * Tk_MakeWindowExist on each of its arguments to force the windows - * to be created. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Forces windows to be created. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestmakeexistCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window mainwin = (Tk_Window) clientData; - int i; - Tk_Window tkwin; - - for (i = 1; i < argc; i++) { - tkwin = Tk_NameToWindow(interp, argv[i], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - Tk_MakeWindowExist(tkwin); - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TestmenubarCmd -- - * - * This procedure implements the "testmenubar" command. It is used - * to test the Unix facilities for creating space above a toplevel - * window for a menubar. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Changes menubar related stuff. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestmenubarCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ -#ifdef __UNIX__ - Tk_Window mainwin = (Tk_Window) clientData; - Tk_Window tkwin, menubar; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " option ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - - if (strcmp(argv[1], "window") == 0) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - "window toplevel menubar\"", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_NameToWindow(interp, argv[2], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - if (argv[3][0] == 0) { - TkUnixSetMenubar(tkwin, NULL); - } else { - menubar = Tk_NameToWindow(interp, argv[3], mainwin); - if (menubar == NULL) { - return TCL_ERROR; - } - TkUnixSetMenubar(tkwin, menubar); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be window", (char *) NULL); - return TCL_ERROR; - } - - return TCL_OK; -#else - interp->result = "testmenubar is supported only under Unix"; - return TCL_ERROR; -#endif -} - -/* - *---------------------------------------------------------------------- - * - * TestmetricsCmd -- - * - * This procedure implements the testmetrics command. It provides - * a way to determine the size of various widget components. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#ifdef __WIN32__ -static int -TestmetricsCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - char buf[200]; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " option ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - - if (strcmp(argv[1], "cyvscroll") == 0) { - sprintf(buf, "%d", GetSystemMetrics(SM_CYVSCROLL)); - Tcl_AppendResult(interp, buf, (char *) NULL); - } else if (strcmp(argv[1], "cxhscroll") == 0) { - sprintf(buf, "%d", GetSystemMetrics(SM_CXHSCROLL)); - Tcl_AppendResult(interp, buf, (char *) NULL); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cxhscroll or cyvscroll", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} -#endif -#ifdef MAC_TCL -static int -TestmetricsCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - TkWindow *winPtr; - char buf[200]; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " option window\"", (char *) NULL); - return TCL_ERROR; - } - - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (winPtr == NULL) { - return TCL_ERROR; - } - - if (strcmp(argv[1], "cyvscroll") == 0) { - sprintf(buf, "%d", ((TkScrollbar *) winPtr->instanceData)->width); - Tcl_AppendResult(interp, buf, (char *) NULL); - } else if (strcmp(argv[1], "cxhscroll") == 0) { - sprintf(buf, "%d", ((TkScrollbar *) winPtr->instanceData)->width); - Tcl_AppendResult(interp, buf, (char *) NULL); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cxhscroll or cyvscroll", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} -#endif - -/* - *---------------------------------------------------------------------- - * - * TestpropCmd -- - * - * This procedure implements the "testprop" command. It fetches - * and prints the value of a property on a window. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestpropCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window mainwin = (Tk_Window) clientData; - int result, actualFormat; - unsigned long bytesAfter, length, value; - Atom actualType, propName; - char *property, *p, *end; - Window w; - char buffer[30]; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " window property\"", (char *) NULL); - return TCL_ERROR; - } - - w = strtoul(argv[1], &end, 0); - propName = Tk_InternAtom(mainwin, argv[2]); - property = NULL; - result = XGetWindowProperty(Tk_Display(mainwin), - w, propName, 0, 100000, False, AnyPropertyType, - &actualType, &actualFormat, &length, - &bytesAfter, (unsigned char **) &property); - if ((result == Success) && (actualType != None)) { - if ((actualFormat == 8) && (actualType == XA_STRING)) { - for (p = property; ((unsigned long)(p-property)) < length; p++) { - if (*p == 0) { - *p = '\n'; - } - } - Tcl_SetResult(interp, property, TCL_VOLATILE); - } else { - for (p = property; length > 0; length--) { - if (actualFormat == 32) { - value = *((long *) p); - p += sizeof(long); - } else if (actualFormat == 16) { - value = 0xffff & (*((short *) p)); - p += sizeof(short); - } else { - value = 0xff & *p; - p += 1; - } - sprintf(buffer, "0x%lx", value); - Tcl_AppendElement(interp, buffer); - } - } - } - if (property != NULL) { - XFree(property); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TestsendCmd -- - * - * This procedure implements the "testsend" command. It provides - * a set of functions for testing the "send" command and support - * procedure in tkSend.c. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Depends on option; see below. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestsendCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr = (TkWindow *) clientData; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " option ?arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - -#if !(defined(__WIN32__) || defined(MAC_TCL)) - if (strcmp(argv[1], "bogus") == 0) { - XChangeProperty(winPtr->dispPtr->display, - RootWindow(winPtr->dispPtr->display, 0), - winPtr->dispPtr->registryProperty, XA_INTEGER, 32, - PropModeReplace, - (unsigned char *) "This is bogus information", 6); - } else if (strcmp(argv[1], "prop") == 0) { - int result, actualFormat; - unsigned long length, bytesAfter; - Atom actualType, propName; - char *property, *p, *end; - Window w; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " prop window name ?value ?\"", (char *) NULL); - return TCL_ERROR; - } - if (strcmp(argv[2], "root") == 0) { - w = RootWindow(winPtr->dispPtr->display, 0); - } else if (strcmp(argv[2], "comm") == 0) { - w = Tk_WindowId(winPtr->dispPtr->commTkwin); - } else { - w = strtoul(argv[2], &end, 0); - } - propName = Tk_InternAtom((Tk_Window) winPtr, argv[3]); - if (argc == 4) { - property = NULL; - result = XGetWindowProperty(winPtr->dispPtr->display, - w, propName, 0, 100000, False, XA_STRING, - &actualType, &actualFormat, &length, - &bytesAfter, (unsigned char **) &property); - if ((result == Success) && (actualType != None) - && (actualFormat == 8) && (actualType == XA_STRING)) { - for (p = property; (p-property) < length; p++) { - if (*p == 0) { - *p = '\n'; - } - } - Tcl_SetResult(interp, property, TCL_VOLATILE); - } - if (property != NULL) { - XFree(property); - } - } else { - if (argv[4][0] == 0) { - XDeleteProperty(winPtr->dispPtr->display, w, propName); - } else { - for (p = argv[4]; *p != 0; p++) { - if (*p == '\n') { - *p = 0; - } - } - XChangeProperty(winPtr->dispPtr->display, - w, propName, XA_STRING, 8, PropModeReplace, - (unsigned char *) argv[4], p-argv[4]); - } - } - } else if (strcmp(argv[1], "serial") == 0) { - sprintf(interp->result, "%d", tkSendSerial+1); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be bogus, prop, or serial", (char *) NULL); - return TCL_ERROR; - } -#endif - return TCL_OK; -} - -#if !(defined(__WIN32__) || defined(MAC_TCL)) -/* - *---------------------------------------------------------------------- - * - * TestwrapperCmd -- - * - * This procedure implements the "testwrapper" command. It - * provides a way from Tcl to determine the extra window Tk adds - * in between the toplevel window and the window decorations. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -TestwrapperCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr, *wrapperPtr; - Tk_Window tkwin; - - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], - " window\"", (char *) NULL); - return TCL_ERROR; - } - - tkwin = (Tk_Window) clientData; - winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); - if (winPtr == NULL) { - return TCL_ERROR; - } - - wrapperPtr = TkpGetWrapperWindow(winPtr); - if (wrapperPtr != NULL) { - TkpPrintWindowId(interp->result, Tk_WindowId(wrapperPtr)); - } - return TCL_OK; -} -#endif diff --git a/generic/tkText.c b/generic/tkText.c deleted file mode 100644 index 67232fb..0000000 --- a/generic/tkText.c +++ /dev/null @@ -1,2264 +0,0 @@ -/* - * tkText.c -- - * - * This module provides a big chunk of the implementation of - * multi-line editable text widgets for Tk. Among other things, - * it provides the Tcl command interfaces to text widgets and - * the display code. The B-tree representation of text is - * implemented elsewhere. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkText.c,v 1.2 1998/09/14 18:23:17 stanton Exp $ - */ - -#include "default.h" -#include "tkPort.h" -#include "tkInt.h" - -#ifdef MAC_TCL -#define Style TkStyle -#define DInfo TkDInfo -#endif - -#include "tkText.h" - -/* - * Information used to parse text configuration options: - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_TEXT_BG_COLOR, Tk_Offset(TkText, border), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_TEXT_BG_MONO, Tk_Offset(TkText, border), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_TEXT_BORDER_WIDTH, Tk_Offset(TkText, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_TEXT_CURSOR, Tk_Offset(TkText, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_TEXT_EXPORT_SELECTION, - Tk_Offset(TkText, exportSelection), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_TEXT_FONT, Tk_Offset(TkText, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_TEXT_FG, Tk_Offset(TkText, fgColor), 0}, - {TK_CONFIG_PIXELS, "-height", "height", "Height", - DEF_TEXT_HEIGHT, Tk_Offset(TkText, height), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_TEXT_HIGHLIGHT_BG, - Tk_Offset(TkText, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_TEXT_HIGHLIGHT, Tk_Offset(TkText, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_TEXT_HIGHLIGHT_WIDTH, Tk_Offset(TkText, highlightWidth), 0}, - {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground", - DEF_TEXT_INSERT_BG, Tk_Offset(TkText, insertBorder), 0}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_TEXT_INSERT_BD_COLOR, Tk_Offset(TkText, insertBorderWidth), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_TEXT_INSERT_BD_MONO, Tk_Offset(TkText, insertBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", - DEF_TEXT_INSERT_OFF_TIME, Tk_Offset(TkText, insertOffTime), 0}, - {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", - DEF_TEXT_INSERT_ON_TIME, Tk_Offset(TkText, insertOnTime), 0}, - {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", - DEF_TEXT_INSERT_WIDTH, Tk_Offset(TkText, insertWidth), 0}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_TEXT_PADX, Tk_Offset(TkText, padX), 0}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_TEXT_PADY, Tk_Offset(TkText, padY), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_TEXT_RELIEF, Tk_Offset(TkText, relief), 0}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_TEXT_SELECT_COLOR, Tk_Offset(TkText, selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_TEXT_SELECT_MONO, Tk_Offset(TkText, selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_TEXT_SELECT_BD_COLOR, Tk_Offset(TkText, selBdString), - TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_TEXT_SELECT_BD_MONO, Tk_Offset(TkText, selBdString), - TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_TEXT_SELECT_FG_COLOR, Tk_Offset(TkText, selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_TEXT_SELECT_FG_MONO, Tk_Offset(TkText, selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_BOOLEAN, "-setgrid", "setGrid", "SetGrid", - DEF_TEXT_SET_GRID, Tk_Offset(TkText, setGrid), 0}, - {TK_CONFIG_PIXELS, "-spacing1", "spacing1", "Spacing", - DEF_TEXT_SPACING1, Tk_Offset(TkText, spacing1), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_PIXELS, "-spacing2", "spacing2", "Spacing", - DEF_TEXT_SPACING2, Tk_Offset(TkText, spacing2), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_PIXELS, "-spacing3", "spacing3", "Spacing", - DEF_TEXT_SPACING3, Tk_Offset(TkText, spacing3), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_TEXT_STATE, Tk_Offset(TkText, state), 0}, - {TK_CONFIG_STRING, "-tabs", "tabs", "Tabs", - DEF_TEXT_TABS, Tk_Offset(TkText, tabOptionString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_TEXT_TAKE_FOCUS, Tk_Offset(TkText, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-width", "width", "Width", - DEF_TEXT_WIDTH, Tk_Offset(TkText, width), 0}, - {TK_CONFIG_UID, "-wrap", "wrap", "Wrap", - DEF_TEXT_WRAP, Tk_Offset(TkText, wrapMode), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_TEXT_XSCROLL_COMMAND, Tk_Offset(TkText, xScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", - DEF_TEXT_YSCROLL_COMMAND, Tk_Offset(TkText, yScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Tk_Uid's used to represent text states: - */ - -Tk_Uid tkTextCharUid = NULL; -Tk_Uid tkTextDisabledUid = NULL; -Tk_Uid tkTextNoneUid = NULL; -Tk_Uid tkTextNormalUid = NULL; -Tk_Uid tkTextWordUid = NULL; - -/* - * Boolean variable indicating whether or not special debugging code - * should be executed. - */ - -int tkTextDebug = 0; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static int ConfigureText _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int argc, char **argv, int flags)); -static int DeleteChars _ANSI_ARGS_((TkText *textPtr, - char *index1String, char *index2String)); -static void DestroyText _ANSI_ARGS_((char *memPtr)); -static void InsertChars _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, char *string)); -static void TextBlinkProc _ANSI_ARGS_((ClientData clientData)); -static void TextCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void TextEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int TextFetchSelection _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static int TextSearchCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -static int TextWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void TextWorldChanged _ANSI_ARGS_(( - ClientData instanceData)); -static int TextDumpCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -static void DumpLine _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int what, TkTextLine *linePtr, - int start, int end, int lineno, char *command)); -static int DumpSegment _ANSI_ARGS_((Tcl_Interp *interp, char *key, - char *value, char * command, int lineno, int offset, - int what)); - -/* - * The structure below defines text class behavior by means of procedures - * that can be invoked from generic window code. - */ - -static TkClassProcs textClass = { - NULL, /* createProc. */ - TextWorldChanged, /* geometryProc. */ - NULL /* modalProc. */ -}; - - -/* - *-------------------------------------------------------------- - * - * Tk_TextCmd -- - * - * This procedure is invoked to process the "text" Tcl command. - * See the user documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -Tk_TextCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; - register TkText *textPtr; - TkTextIndex startIndex; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * Perform once-only initialization: - */ - - if (tkTextNormalUid == NULL) { - tkTextCharUid = Tk_GetUid("char"); - tkTextDisabledUid = Tk_GetUid("disabled"); - tkTextNoneUid = Tk_GetUid("none"); - tkTextNormalUid = Tk_GetUid("normal"); - tkTextWordUid = Tk_GetUid("word"); - } - - /* - * Create the window. - */ - - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { - return TCL_ERROR; - } - - textPtr = (TkText *) ckalloc(sizeof(TkText)); - textPtr->tkwin = new; - textPtr->display = Tk_Display(new); - textPtr->interp = interp; - textPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(textPtr->tkwin), TextWidgetCmd, - (ClientData) textPtr, TextCmdDeletedProc); - textPtr->tree = TkBTreeCreate(textPtr); - Tcl_InitHashTable(&textPtr->tagTable, TCL_STRING_KEYS); - textPtr->numTags = 0; - Tcl_InitHashTable(&textPtr->markTable, TCL_STRING_KEYS); - Tcl_InitHashTable(&textPtr->windowTable, TCL_STRING_KEYS); - Tcl_InitHashTable(&textPtr->imageTable, TCL_STRING_KEYS); - textPtr->state = tkTextNormalUid; - textPtr->border = NULL; - textPtr->borderWidth = 0; - textPtr->padX = 0; - textPtr->padY = 0; - textPtr->relief = TK_RELIEF_FLAT; - textPtr->highlightWidth = 0; - textPtr->highlightBgColorPtr = NULL; - textPtr->highlightColorPtr = NULL; - textPtr->cursor = None; - textPtr->fgColor = NULL; - textPtr->tkfont = NULL; - textPtr->charWidth = 1; - textPtr->spacing1 = 0; - textPtr->spacing2 = 0; - textPtr->spacing3 = 0; - textPtr->tabOptionString = NULL; - textPtr->tabArrayPtr = NULL; - textPtr->wrapMode = tkTextCharUid; - textPtr->width = 0; - textPtr->height = 0; - textPtr->setGrid = 0; - textPtr->prevWidth = Tk_Width(new); - textPtr->prevHeight = Tk_Height(new); - TkTextCreateDInfo(textPtr); - TkTextMakeIndex(textPtr->tree, 0, 0, &startIndex); - TkTextSetYView(textPtr, &startIndex, 0); - textPtr->selTagPtr = NULL; - textPtr->selBorder = NULL; - textPtr->selBdString = NULL; - textPtr->selFgColorPtr = NULL; - textPtr->exportSelection = 1; - textPtr->abortSelections = 0; - textPtr->insertMarkPtr = NULL; - textPtr->insertBorder = NULL; - textPtr->insertWidth = 0; - textPtr->insertBorderWidth = 0; - textPtr->insertOnTime = 0; - textPtr->insertOffTime = 0; - textPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - textPtr->bindingTable = NULL; - textPtr->currentMarkPtr = NULL; - textPtr->pickEvent.type = LeaveNotify; - textPtr->pickEvent.xcrossing.x = 0; - textPtr->pickEvent.xcrossing.y = 0; - textPtr->numCurTags = 0; - textPtr->curTagArrayPtr = NULL; - textPtr->takeFocus = NULL; - textPtr->xScrollCmd = NULL; - textPtr->yScrollCmd = NULL; - textPtr->flags = 0; - - /* - * Create the "sel" tag and the "current" and "insert" marks. - */ - - textPtr->selTagPtr = TkTextCreateTag(textPtr, "sel"); - textPtr->selTagPtr->reliefString = (char *) ckalloc(7); - strcpy(textPtr->selTagPtr->reliefString, DEF_TEXT_SELECT_RELIEF); - textPtr->selTagPtr->relief = TK_RELIEF_RAISED; - textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &startIndex); - textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &startIndex); - - Tk_SetClass(textPtr->tkwin, "Text"); - TkSetClassProcs(textPtr->tkwin, &textClass, (ClientData) textPtr); - Tk_CreateEventHandler(textPtr->tkwin, - ExposureMask|StructureNotifyMask|FocusChangeMask, - TextEventProc, (ClientData) textPtr); - Tk_CreateEventHandler(textPtr->tkwin, KeyPressMask|KeyReleaseMask - |ButtonPressMask|ButtonReleaseMask|EnterWindowMask - |LeaveWindowMask|PointerMotionMask|VirtualEventMask, - TkTextBindProc, (ClientData) textPtr); - Tk_CreateSelHandler(textPtr->tkwin, XA_PRIMARY, XA_STRING, - TextFetchSelection, (ClientData) textPtr, XA_STRING); - if (ConfigureText(interp, textPtr, argc-2, argv+2, 0) != TCL_OK) { - Tk_DestroyWindow(textPtr->tkwin); - return TCL_ERROR; - } - interp->result = Tk_PathName(textPtr->tkwin); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TextWidgetCmd -- - * - * This procedure is invoked to process the Tcl command - * that corresponds to a text widget. See the user - * documentation for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -static int -TextWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - register TkText *textPtr = (TkText *) clientData; - int result = TCL_OK; - size_t length; - int c; - TkTextIndex index1, index2; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_Preserve((ClientData) textPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - int x, y, width, height; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox index\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (TkTextCharBbox(textPtr, &index1, &x, &y, &width, &height) == 0) { - sprintf(interp->result, "%d %d %d %d", x, y, width, height); - } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - result = Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs, - (char *) textPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "compare", length) == 0) - && (length >= 3)) { - int relation, value; - char *p; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " compare index1 op index2\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if ((TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) - || (TkTextGetIndex(interp, textPtr, argv[4], &index2) - != TCL_OK)) { - result = TCL_ERROR; - goto done; - } - relation = TkTextIndexCmp(&index1, &index2); - p = argv[3]; - if (p[0] == '<') { - value = (relation < 0); - if ((p[1] == '=') && (p[2] == 0)) { - value = (relation <= 0); - } else if (p[1] != 0) { - compareError: - Tcl_AppendResult(interp, "bad comparison operator \"", - argv[3], "\": must be <, <=, ==, >=, >, or !=", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - } else if (p[0] == '>') { - value = (relation > 0); - if ((p[1] == '=') && (p[2] == 0)) { - value = (relation >= 0); - } else if (p[1] != 0) { - goto compareError; - } - } else if ((p[0] == '=') && (p[1] == '=') && (p[2] == 0)) { - value = (relation == 0); - } else if ((p[0] == '!') && (p[1] == '=') && (p[2] == 0)) { - value = (relation != 0); - } else { - goto compareError; - } - interp->result = (value) ? "1" : "0"; - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) textPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) textPtr, argv[2], 0); - } else { - result = ConfigureText(interp, textPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "debug", length) == 0) - && (length >= 3)) { - if (argc > 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " debug boolean\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (argc == 2) { - interp->result = (tkBTreeDebug) ? "1" : "0"; - } else { - if (Tcl_GetBoolean(interp, argv[2], &tkBTreeDebug) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - tkTextDebug = tkBTreeDebug; - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0) - && (length >= 3)) { - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete index1 ?index2?\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (textPtr->state == tkTextNormalUid) { - result = DeleteChars(textPtr, argv[2], - (argc == 4) ? argv[3] : (char *) NULL); - } - } else if ((c == 'd') && (strncmp(argv[1], "dlineinfo", length) == 0) - && (length >= 2)) { - int x, y, width, height, base; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dlineinfo index\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (TkTextDLineInfo(textPtr, &index1, &x, &y, &width, &height, &base) - == 0) { - sprintf(interp->result, "%d %d %d %d %d", x, y, width, - height, base); - } - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get index1 ?index2?\"", (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (argc == 3) { - index2 = index1; - TkTextIndexForwChars(&index2, 1, &index2); - } else if (TkTextGetIndex(interp, textPtr, argv[3], &index2) - != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (TkTextIndexCmp(&index1, &index2) >= 0) { - goto done; - } - while (1) { - int offset, last, savedChar; - TkTextSegment *segPtr; - - segPtr = TkTextIndexToSeg(&index1, &offset); - last = segPtr->size; - if (index1.linePtr == index2.linePtr) { - int last2; - - if (index2.charIndex == index1.charIndex) { - break; - } - last2 = index2.charIndex - index1.charIndex + offset; - if (last2 < last) { - last = last2; - } - } - if (segPtr->typePtr == &tkTextCharType) { - savedChar = segPtr->body.chars[last]; - segPtr->body.chars[last] = 0; - Tcl_AppendResult(interp, segPtr->body.chars + offset, - (char *) NULL); - segPtr->body.chars[last] = savedChar; - } - TkTextIndexForwChars(&index1, last-offset, &index1); - } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index index\"", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - TkTextPrintIndex(&index1, interp->result); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int i, j, numTags; - char **tagNames; - TkTextTag **oldTagArrayPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], - " insert index chars ?tagList chars tagList ...?\"", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index1) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (textPtr->state == tkTextNormalUid) { - for (j = 3; j < argc; j += 2) { - InsertChars(textPtr, &index1, argv[j]); - if (argc > (j+1)) { - TkTextIndexForwChars(&index1, (int) strlen(argv[j]), - &index2); - oldTagArrayPtr = TkBTreeGetTags(&index1, &numTags); - if (oldTagArrayPtr != NULL) { - for (i = 0; i < numTags; i++) { - TkBTreeTag(&index1, &index2, oldTagArrayPtr[i], 0); - } - ckfree((char *) oldTagArrayPtr); - } - if (Tcl_SplitList(interp, argv[j+1], &numTags, &tagNames) - != TCL_OK) { - result = TCL_ERROR; - goto done; - } - for (i = 0; i < numTags; i++) { - TkBTreeTag(&index1, &index2, - TkTextCreateTag(textPtr, tagNames[i]), 1); - } - ckfree((char *) tagNames); - index1 = index2; - } - } - } - } else if ((c == 'd') && (strncmp(argv[1], "dump", length) == 0)) { - result = TextDumpCmd(textPtr, interp, argc, argv); - } else if ((c == 'i') && (strncmp(argv[1], "image", length) == 0)) { - result = TkTextImageCmd(textPtr, interp, argc, argv); - } else if ((c == 'm') && (strncmp(argv[1], "mark", length) == 0)) { - result = TkTextMarkCmd(textPtr, interp, argc, argv); - } else if ((c == 's') && (strcmp(argv[1], "scan") == 0) && (length >= 2)) { - result = TkTextScanCmd(textPtr, interp, argc, argv); - } else if ((c == 's') && (strcmp(argv[1], "search") == 0) - && (length >= 3)) { - result = TextSearchCmd(textPtr, interp, argc, argv); - } else if ((c == 's') && (strcmp(argv[1], "see") == 0) && (length >= 3)) { - result = TkTextSeeCmd(textPtr, interp, argc, argv); - } else if ((c == 't') && (strcmp(argv[1], "tag") == 0)) { - result = TkTextTagCmd(textPtr, interp, argc, argv); - } else if ((c == 'w') && (strncmp(argv[1], "window", length) == 0)) { - result = TkTextWindowCmd(textPtr, interp, argc, argv); - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - result = TkTextXviewCmd(textPtr, interp, argc, argv); - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0) - && (length >= 2)) { - result = TkTextYviewCmd(textPtr, interp, argc, argv); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be bbox, cget, compare, configure, debug, delete, ", - "dlineinfo, get, image, index, insert, mark, scan, search, see, ", - "tag, window, xview, or yview", - (char *) NULL); - result = TCL_ERROR; - } - - done: - Tcl_Release((ClientData) textPtr); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * DestroyText -- - * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a text at a safe time - * (when no-one is using it anymore). - * - * Results: - * None. - * - * Side effects: - * Everything associated with the text is freed up. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyText(memPtr) - char *memPtr; /* Info about text widget. */ -{ - register TkText *textPtr = (TkText *) memPtr; - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - TkTextTag *tagPtr; - - /* - * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related - * stuff. Special note: free up display-related information - * before deleting the B-tree, since display-related stuff - * may refer to stuff in the B-tree. - */ - - TkTextFreeDInfo(textPtr); - TkBTreeDestroy(textPtr->tree); - for (hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); - TkTextFreeTag(textPtr, tagPtr); - } - Tcl_DeleteHashTable(&textPtr->tagTable); - for (hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - ckfree((char *) Tcl_GetHashValue(hPtr)); - } - Tcl_DeleteHashTable(&textPtr->markTable); - if (textPtr->tabArrayPtr != NULL) { - ckfree((char *) textPtr->tabArrayPtr); - } - if (textPtr->insertBlinkHandler != NULL) { - Tcl_DeleteTimerHandler(textPtr->insertBlinkHandler); - } - if (textPtr->bindingTable != NULL) { - Tk_DeleteBindingTable(textPtr->bindingTable); - } - - /* - * NOTE: do NOT free up selBorder, selBdString, or selFgColorPtr: - * they are duplicates of information in the "sel" tag, which was - * freed up as part of deleting the tags above. - */ - - textPtr->selBorder = NULL; - textPtr->selBdString = NULL; - textPtr->selFgColorPtr = NULL; - Tk_FreeOptions(configSpecs, (char *) textPtr, textPtr->display, 0); - ckfree((char *) textPtr); -} - -/* - *---------------------------------------------------------------------- - * - * ConfigureText -- - * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a text widget. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. - * - * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for textPtr; old resources get freed, if there - * were any. - * - *---------------------------------------------------------------------- - */ - -static int -ConfigureText(interp, textPtr, argc, argv, flags) - Tcl_Interp *interp; /* Used for error reporting. */ - register TkText *textPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ -{ - int oldExport = textPtr->exportSelection; - - if (Tk_ConfigureWidget(interp, textPtr->tkwin, configSpecs, - argc, argv, (char *) textPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - - /* - * A few other options also need special processing, such as parsing - * the geometry and setting the background from a 3-D border. - */ - - if ((textPtr->state != tkTextNormalUid) - && (textPtr->state != tkTextDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", textPtr->state, - "\": must be normal or disabled", (char *) NULL); - textPtr->state = tkTextNormalUid; - return TCL_ERROR; - } - - if ((textPtr->wrapMode != tkTextCharUid) - && (textPtr->wrapMode != tkTextNoneUid) - && (textPtr->wrapMode != tkTextWordUid)) { - Tcl_AppendResult(interp, "bad wrap mode \"", textPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - textPtr->wrapMode = tkTextCharUid; - return TCL_ERROR; - } - - Tk_SetBackgroundFromBorder(textPtr->tkwin, textPtr->border); - - /* - * Don't allow negative spacings. - */ - - if (textPtr->spacing1 < 0) { - textPtr->spacing1 = 0; - } - if (textPtr->spacing2 < 0) { - textPtr->spacing2 = 0; - } - if (textPtr->spacing3 < 0) { - textPtr->spacing3 = 0; - } - - /* - * Parse tab stops. - */ - - if (textPtr->tabArrayPtr != NULL) { - ckfree((char *) textPtr->tabArrayPtr); - textPtr->tabArrayPtr = NULL; - } - if (textPtr->tabOptionString != NULL) { - textPtr->tabArrayPtr = TkTextGetTabs(interp, textPtr->tkwin, - textPtr->tabOptionString); - if (textPtr->tabArrayPtr == NULL) { - Tcl_AddErrorInfo(interp,"\n (while processing -tabs option)"); - return TCL_ERROR; - } - } - - /* - * Make sure that configuration options are properly mirrored - * between the widget record and the "sel" tags. NOTE: we don't - * have to free up information during the mirroring; old - * information was freed when it was replaced in the widget - * record. - */ - - textPtr->selTagPtr->border = textPtr->selBorder; - if (textPtr->selTagPtr->bdString != textPtr->selBdString) { - textPtr->selTagPtr->bdString = textPtr->selBdString; - if (textPtr->selBdString != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, textPtr->selBdString, - &textPtr->selTagPtr->borderWidth) != TCL_OK) { - return TCL_ERROR; - } - if (textPtr->selTagPtr->borderWidth < 0) { - textPtr->selTagPtr->borderWidth = 0; - } - } - } - textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr; - textPtr->selTagPtr->affectsDisplay = 0; - if ((textPtr->selTagPtr->border != NULL) - || (textPtr->selTagPtr->bdString != NULL) - || (textPtr->selTagPtr->reliefString != NULL) - || (textPtr->selTagPtr->bgStipple != None) - || (textPtr->selTagPtr->fgColor != NULL) - || (textPtr->selTagPtr->tkfont != None) - || (textPtr->selTagPtr->fgStipple != None) - || (textPtr->selTagPtr->justifyString != NULL) - || (textPtr->selTagPtr->lMargin1String != NULL) - || (textPtr->selTagPtr->lMargin2String != NULL) - || (textPtr->selTagPtr->offsetString != NULL) - || (textPtr->selTagPtr->overstrikeString != NULL) - || (textPtr->selTagPtr->rMarginString != NULL) - || (textPtr->selTagPtr->spacing1String != NULL) - || (textPtr->selTagPtr->spacing2String != NULL) - || (textPtr->selTagPtr->spacing3String != NULL) - || (textPtr->selTagPtr->tabString != NULL) - || (textPtr->selTagPtr->underlineString != NULL) - || (textPtr->selTagPtr->wrapMode != NULL)) { - textPtr->selTagPtr->affectsDisplay = 1; - } - TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, - textPtr->selTagPtr, 1); - - /* - * Claim the selection if we've suddenly started exporting it and there - * are tagged characters. - */ - - if (textPtr->exportSelection && (!oldExport)) { - TkTextSearch search; - TkTextIndex first, last; - - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, - TkBTreeNumLines(textPtr->tree), 0, &last); - TkBTreeStartSearch(&first, &last, textPtr->selTagPtr, &search); - if (TkBTreeCharTagged(&first, textPtr->selTagPtr) - || TkBTreeNextTag(&search)) { - Tk_OwnSelection(textPtr->tkwin, XA_PRIMARY, TkTextLostSelection, - (ClientData) textPtr); - textPtr->flags |= GOT_SELECTION; - } - } - - /* - * Register the desired geometry for the window, and arrange for - * the window to be redisplayed. - */ - - if (textPtr->width <= 0) { - textPtr->width = 1; - } - if (textPtr->height <= 0) { - textPtr->height = 1; - } - TextWorldChanged((ClientData) textPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * TextWorldChanged -- - * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. - * - * Results: - * None. - * - * Side effects: - * Configures all tags in the Text with a empty argc/argv, for - * the side effect of causing all the items to recompute their - * geometry and to be redisplayed. - * - *--------------------------------------------------------------------------- - */ - -static void -TextWorldChanged(instanceData) - ClientData instanceData; /* Information about widget. */ -{ - TkText *textPtr; - Tk_FontMetrics fm; - - textPtr = (TkText *) instanceData; - - textPtr->charWidth = Tk_TextWidth(textPtr->tkfont, "0", 1); - if (textPtr->charWidth <= 0) { - textPtr->charWidth = 1; - } - Tk_GetFontMetrics(textPtr->tkfont, &fm); - Tk_GeometryRequest(textPtr->tkwin, - textPtr->width * textPtr->charWidth + 2*textPtr->borderWidth - + 2*textPtr->padX + 2*textPtr->highlightWidth, - textPtr->height * (fm.linespace + textPtr->spacing1 - + textPtr->spacing3) + 2*textPtr->borderWidth - + 2*textPtr->padY + 2*textPtr->highlightWidth); - Tk_SetInternalBorder(textPtr->tkwin, - textPtr->borderWidth + textPtr->highlightWidth); - if (textPtr->setGrid) { - Tk_SetGrid(textPtr->tkwin, textPtr->width, textPtr->height, - textPtr->charWidth, fm.linespace); - } else { - Tk_UnsetGrid(textPtr->tkwin); - } - - TkTextRelayoutWindow(textPtr); -} - -/* - *-------------------------------------------------------------- - * - * TextEventProc -- - * - * This procedure is invoked by the Tk dispatcher on - * structure changes to a text. For texts with 3D - * borders, this procedure is also invoked for exposures. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -TextEventProc(clientData, eventPtr) - ClientData clientData; /* Information about window. */ - register XEvent *eventPtr; /* Information about event. */ -{ - register TkText *textPtr = (TkText *) clientData; - TkTextIndex index, index2; - - if (eventPtr->type == Expose) { - TkTextRedrawRegion(textPtr, eventPtr->xexpose.x, - eventPtr->xexpose.y, eventPtr->xexpose.width, - eventPtr->xexpose.height); - } else if (eventPtr->type == ConfigureNotify) { - if ((textPtr->prevWidth != Tk_Width(textPtr->tkwin)) - || (textPtr->prevHeight != Tk_Height(textPtr->tkwin))) { - TkTextRelayoutWindow(textPtr); - textPtr->prevWidth = Tk_Width(textPtr->tkwin); - textPtr->prevHeight = Tk_Height(textPtr->tkwin); - } - } else if (eventPtr->type == DestroyNotify) { - if (textPtr->tkwin != NULL) { - if (textPtr->setGrid) { - Tk_UnsetGrid(textPtr->tkwin); - } - textPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(textPtr->interp, - textPtr->widgetCmd); - } - Tcl_EventuallyFree((ClientData) textPtr, DestroyText); - } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { - if (eventPtr->xfocus.detail != NotifyInferior) { - Tcl_DeleteTimerHandler(textPtr->insertBlinkHandler); - if (eventPtr->type == FocusIn) { - textPtr->flags |= GOT_FOCUS | INSERT_ON; - if (textPtr->insertOffTime != 0) { - textPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - textPtr->insertOnTime, TextBlinkProc, - (ClientData) textPtr); - } - } else { - textPtr->flags &= ~(GOT_FOCUS | INSERT_ON); - textPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - } -#ifndef ALWAYS_SHOW_SELECTION - TkTextRedrawTag(textPtr, NULL, NULL, textPtr->selTagPtr, 1); -#endif - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextIndexForwChars(&index, 1, &index2); - TkTextChanged(textPtr, &index, &index2); - if (textPtr->highlightWidth > 0) { - TkTextRedrawRegion(textPtr, 0, 0, textPtr->highlightWidth, - textPtr->highlightWidth); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TextCmdDeletedProc -- - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ - -static void -TextCmdDeletedProc(clientData) - ClientData clientData; /* Pointer to widget record for widget. */ -{ - TkText *textPtr = (TkText *) clientData; - Tk_Window tkwin = textPtr->tkwin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (tkwin != NULL) { - if (textPtr->setGrid) { - Tk_UnsetGrid(textPtr->tkwin); - } - textPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); - } -} - -/* - *---------------------------------------------------------------------- - * - * InsertChars -- - * - * This procedure implements most of the functionality of the - * "insert" widget command. - * - * Results: - * None. - * - * Side effects: - * The characters in "string" get added to the text just before - * the character indicated by "indexPtr". - * - *---------------------------------------------------------------------- - */ - -static void -InsertChars(textPtr, indexPtr, string) - TkText *textPtr; /* Overall information about text widget. */ - TkTextIndex *indexPtr; /* Where to insert new characters. May be - * modified and/or invalidated. */ - char *string; /* Null-terminated string containing new - * information to add to text. */ -{ - int lineIndex, resetView, offset; - TkTextIndex newTop; - - /* - * Don't allow insertions on the last (dummy) line of the text. - */ - - lineIndex = TkBTreeLineIndex(indexPtr->linePtr); - if (lineIndex == TkBTreeNumLines(textPtr->tree)) { - lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, indexPtr); - } - - /* - * Notify the display module that lines are about to change, then do - * the insertion. If the insertion occurs on the top line of the - * widget (textPtr->topIndex), then we have to recompute topIndex - * after the insertion, since the insertion could invalidate it. - */ - - resetView = offset = 0; - if (indexPtr->linePtr == textPtr->topIndex.linePtr) { - resetView = 1; - offset = textPtr->topIndex.charIndex; - if (offset > indexPtr->charIndex) { - offset += strlen(string); - } - } - TkTextChanged(textPtr, indexPtr, indexPtr); - TkBTreeInsertChars(indexPtr, string); - if (resetView) { - TkTextMakeIndex(textPtr->tree, lineIndex, 0, &newTop); - TkTextIndexForwChars(&newTop, offset, &newTop); - TkTextSetYView(textPtr, &newTop, 0); - } - - /* - * Invalidate any selection retrievals in progress. - */ - - textPtr->abortSelections = 1; -} - -/* - *---------------------------------------------------------------------- - * - * DeleteChars -- - * - * This procedure implements most of the functionality of the - * "delete" widget command. - * - * Results: - * Returns a standard Tcl result, and leaves an error message - * in textPtr->interp if there is an error. - * - * Side effects: - * Characters get deleted from the text. - * - *---------------------------------------------------------------------- - */ - -static int -DeleteChars(textPtr, index1String, index2String) - TkText *textPtr; /* Overall information about text widget. */ - char *index1String; /* String describing location of first - * character to delete. */ - char *index2String; /* String describing location of last - * character to delete. NULL means just - * delete the one character given by - * index1String. */ -{ - int line1, line2, line, charIndex, resetView; - TkTextIndex index1, index2; - - /* - * Parse the starting and stopping indices. - */ - - if (TkTextGetIndex(textPtr->interp, textPtr, index1String, &index1) - != TCL_OK) { - return TCL_ERROR; - } - if (index2String != NULL) { - if (TkTextGetIndex(textPtr->interp, textPtr, index2String, &index2) - != TCL_OK) { - return TCL_ERROR; - } - } else { - index2 = index1; - TkTextIndexForwChars(&index2, 1, &index2); - } - - /* - * Make sure there's really something to delete. - */ - - if (TkTextIndexCmp(&index1, &index2) >= 0) { - return TCL_OK; - } - - /* - * The code below is ugly, but it's needed to make sure there - * is always a dummy empty line at the end of the text. If the - * final newline of the file (just before the dummy line) is being - * deleted, then back up index to just before the newline. If - * there is a newline just before the first character being deleted, - * then back up the first index too, so that an even number of lines - * gets deleted. Furthermore, remove any tags that are present on - * the newline that isn't going to be deleted after all (this simulates - * deleting the newline and then adding a "clean" one back again). - */ - - line1 = TkBTreeLineIndex(index1.linePtr); - line2 = TkBTreeLineIndex(index2.linePtr); - if (line2 == TkBTreeNumLines(textPtr->tree)) { - TkTextTag **arrayPtr; - int arraySize, i; - TkTextIndex oldIndex2; - - oldIndex2 = index2; - TkTextIndexBackChars(&oldIndex2, 1, &index2); - line2--; - if ((index1.charIndex == 0) && (line1 != 0)) { - TkTextIndexBackChars(&index1, 1, &index1); - line1--; - } - arrayPtr = TkBTreeGetTags(&index2, &arraySize); - if (arrayPtr != NULL) { - for (i = 0; i < arraySize; i++) { - TkBTreeTag(&index2, &oldIndex2, arrayPtr[i], 0); - } - ckfree((char *) arrayPtr); - } - } - - /* - * Tell the display what's about to happen so it can discard - * obsolete display information, then do the deletion. Also, - * if the deletion involves the top line on the screen, then - * we have to reset the view (the deletion will invalidate - * textPtr->topIndex). Compute what the new first character - * will be, then do the deletion, then reset the view. - */ - - TkTextChanged(textPtr, &index1, &index2); - resetView = line = charIndex = 0; - if (TkTextIndexCmp(&index2, &textPtr->topIndex) >= 0) { - if (TkTextIndexCmp(&index1, &textPtr->topIndex) <= 0) { - /* - * Deletion range straddles topIndex: use the beginning - * of the range as the new topIndex. - */ - - resetView = 1; - line = line1; - charIndex = index1.charIndex; - } else if (index1.linePtr == textPtr->topIndex.linePtr) { - /* - * Deletion range starts on top line but after topIndex. - * Use the current topIndex as the new one. - */ - - resetView = 1; - line = line1; - charIndex = textPtr->topIndex.charIndex; - } - } else if (index2.linePtr == textPtr->topIndex.linePtr) { - /* - * Deletion range ends on top line but before topIndex. - * Figure out what will be the new character index for - * the character currently pointed to by topIndex. - */ - - resetView = 1; - line = line2; - charIndex = textPtr->topIndex.charIndex; - if (index1.linePtr != index2.linePtr) { - charIndex -= index2.charIndex; - } else { - charIndex -= (index2.charIndex - index1.charIndex); - } - } - TkBTreeDeleteChars(&index1, &index2); - if (resetView) { - TkTextMakeIndex(textPtr->tree, line, charIndex, &index1); - TkTextSetYView(textPtr, &index1, 0); - } - - /* - * Invalidate any selection retrievals in progress. - */ - - textPtr->abortSelections = 1; - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TextFetchSelection -- - * - * This procedure is called back by Tk when the selection is - * requested by someone. It returns part or all of the selection - * in a buffer provided by the caller. - * - * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -TextFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about text widget. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ -{ - register TkText *textPtr = (TkText *) clientData; - TkTextIndex eof; - int count, chunkSize, offsetInSeg; - TkTextSearch search; - TkTextSegment *segPtr; - - if (!textPtr->exportSelection) { - return -1; - } - - /* - * Find the beginning of the next range of selected text. Note: if - * the selection is being retrieved in multiple pieces (offset != 0) - * and some modification has been made to the text that affects the - * selection then reject the selection request (make 'em start over - * again). - */ - - if (offset == 0) { - TkTextMakeIndex(textPtr->tree, 0, 0, &textPtr->selIndex); - textPtr->abortSelections = 0; - } else if (textPtr->abortSelections) { - return 0; - } - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &eof); - TkBTreeStartSearch(&textPtr->selIndex, &eof, textPtr->selTagPtr, &search); - if (!TkBTreeCharTagged(&textPtr->selIndex, textPtr->selTagPtr)) { - if (!TkBTreeNextTag(&search)) { - if (offset == 0) { - return -1; - } else { - return 0; - } - } - textPtr->selIndex = search.curIndex; - } - - /* - * Each iteration through the outer loop below scans one selected range. - * Each iteration through the inner loop scans one segment in the - * selected range. - */ - - count = 0; - while (1) { - /* - * Find the end of the current range of selected text. - */ - - if (!TkBTreeNextTag(&search)) { - panic("TextFetchSelection couldn't find end of range"); - } - - /* - * Copy information from character segments into the buffer - * until either we run out of space in the buffer or we get - * to the end of this range of text. - */ - - while (1) { - if (maxBytes == 0) { - goto done; - } - segPtr = TkTextIndexToSeg(&textPtr->selIndex, &offsetInSeg); - chunkSize = segPtr->size - offsetInSeg; - if (chunkSize > maxBytes) { - chunkSize = maxBytes; - } - if (textPtr->selIndex.linePtr == search.curIndex.linePtr) { - int leftInRange; - - leftInRange = search.curIndex.charIndex - - textPtr->selIndex.charIndex; - if (leftInRange < chunkSize) { - chunkSize = leftInRange; - if (chunkSize <= 0) { - break; - } - } - } - if (segPtr->typePtr == &tkTextCharType) { - memcpy((VOID *) buffer, (VOID *) (segPtr->body.chars - + offsetInSeg), (size_t) chunkSize); - buffer += chunkSize; - maxBytes -= chunkSize; - count += chunkSize; - } - TkTextIndexForwChars(&textPtr->selIndex, chunkSize, - &textPtr->selIndex); - } - - /* - * Find the beginning of the next range of selected text. - */ - - if (!TkBTreeNextTag(&search)) { - break; - } - textPtr->selIndex = search.curIndex; - } - - done: - *buffer = 0; - return count; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextLostSelection -- - * - * This procedure is called back by Tk when the selection is - * grabbed away from a text widget. On Windows and Mac systems, we - * want to remember the selection for the next time the focus - * enters the window. On Unix, just remove the "sel" tag from - * everything in the widget. - * - * Results: - * None. - * - * Side effects: - * The "sel" tag is cleared from the window. - * - *---------------------------------------------------------------------- - */ - -void -TkTextLostSelection(clientData) - ClientData clientData; /* Information about text widget. */ -{ - register TkText *textPtr = (TkText *) clientData; -#ifdef ALWAYS_SHOW_SELECTION - TkTextIndex start, end; - - if (!textPtr->exportSelection) { - return; - } - - /* - * On Windows and Mac systems, we want to remember the selection - * for the next time the focus enters the window. On Unix, - * just remove the "sel" tag from everything in the widget. - */ - - TkTextMakeIndex(textPtr->tree, 0, 0, &start); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &end); - TkTextRedrawTag(textPtr, &start, &end, textPtr->selTagPtr, 1); - TkBTreeTag(&start, &end, textPtr->selTagPtr, 0); -#endif - textPtr->flags &= ~GOT_SELECTION; -} - -/* - *---------------------------------------------------------------------- - * - * TextBlinkProc -- - * - * This procedure is called as a timer handler to blink the - * insertion cursor off and on. - * - * Results: - * None. - * - * Side effects: - * The cursor gets turned on or off, redisplay gets invoked, - * and this procedure reschedules itself. - * - *---------------------------------------------------------------------- - */ - -static void -TextBlinkProc(clientData) - ClientData clientData; /* Pointer to record describing text. */ -{ - register TkText *textPtr = (TkText *) clientData; - TkTextIndex index; - int x, y, w, h; - - if (!(textPtr->flags & GOT_FOCUS) || (textPtr->insertOffTime == 0)) { - return; - } - if (textPtr->flags & INSERT_ON) { - textPtr->flags &= ~INSERT_ON; - textPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - textPtr->insertOffTime, TextBlinkProc, (ClientData) textPtr); - } else { - textPtr->flags |= INSERT_ON; - textPtr->insertBlinkHandler = Tcl_CreateTimerHandler( - textPtr->insertOnTime, TextBlinkProc, (ClientData) textPtr); - } - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextCharBbox(textPtr, &index, &x, &y, &w, &h); - TkTextRedrawRegion(textPtr, x - textPtr->insertWidth / 2, y, - textPtr->insertWidth, h); -} - -/* - *---------------------------------------------------------------------- - * - * TextSearchCmd -- - * - * This procedure is invoked to process the "search" widget command - * for text widgets. See the user documentation for details on what - * it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -static int -TextSearchCmd(textPtr, interp, argc, argv) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - int backwards, exact, c, i, argsLeft, noCase, leftToScan; - size_t length; - int numLines, startingLine, startingChar, lineNum, firstChar, lastChar; - int code, matchLength, matchChar, passes, stopLine, searchWholeText; - int patLength; - char *arg, *pattern, *varName, *p, *startOfLine; - char buffer[20]; - TkTextIndex index, stopIndex; - Tcl_DString line, patDString; - TkTextSegment *segPtr; - TkTextLine *linePtr; - Tcl_RegExp regexp = NULL; /* Initialization needed only to - * prevent compiler warning. */ - - /* - * Parse switches and other arguments. - */ - - exact = 1; - backwards = 0; - noCase = 0; - varName = NULL; - for (i = 2; i < argc; i++) { - arg = argv[i]; - if (arg[0] != '-') { - break; - } - length = strlen(arg); - if (length < 2) { - badSwitch: - Tcl_AppendResult(interp, "bad switch \"", arg, - "\": must be -forward, -backward, -exact, -regexp, ", - "-nocase, -count, or --", (char *) NULL); - return TCL_ERROR; - } - c = arg[1]; - if ((c == 'b') && (strncmp(argv[i], "-backwards", length) == 0)) { - backwards = 1; - } else if ((c == 'c') && (strncmp(argv[i], "-count", length) == 0)) { - if (i >= (argc-1)) { - interp->result = "no value given for \"-count\" option"; - return TCL_ERROR; - } - i++; - varName = argv[i]; - } else if ((c == 'e') && (strncmp(argv[i], "-exact", length) == 0)) { - exact = 1; - } else if ((c == 'f') && (strncmp(argv[i], "-forwards", length) == 0)) { - backwards = 0; - } else if ((c == 'n') && (strncmp(argv[i], "-nocase", length) == 0)) { - noCase = 1; - } else if ((c == 'r') && (strncmp(argv[i], "-regexp", length) == 0)) { - exact = 0; - } else if ((c == '-') && (strncmp(argv[i], "--", length) == 0)) { - i++; - break; - } else { - goto badSwitch; - } - } - argsLeft = argc - (i+2); - if ((argsLeft != 0) && (argsLeft != 1)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " search ?switches? pattern index ?stopIndex?", - (char *) NULL); - return TCL_ERROR; - } - pattern = argv[i]; - - /* - * Convert the pattern to lower-case if we're supposed to ignore case. - */ - - if (noCase) { - Tcl_DStringInit(&patDString); - Tcl_DStringAppend(&patDString, pattern, -1); - pattern = Tcl_DStringValue(&patDString); - for (p = pattern; *p != 0; p++) { - if (isupper(UCHAR(*p))) { - *p = tolower(UCHAR(*p)); - } - } - } - - if (TkTextGetIndex(interp, textPtr, argv[i+1], &index) != TCL_OK) { - return TCL_ERROR; - } - numLines = TkBTreeNumLines(textPtr->tree); - startingLine = TkBTreeLineIndex(index.linePtr); - startingChar = index.charIndex; - if (startingLine >= numLines) { - if (backwards) { - startingLine = TkBTreeNumLines(textPtr->tree) - 1; - startingChar = TkBTreeCharsInLine(TkBTreeFindLine(textPtr->tree, - startingLine)); - } else { - startingLine = 0; - startingChar = 0; - } - } - if (argsLeft == 1) { - if (TkTextGetIndex(interp, textPtr, argv[i+2], &stopIndex) != TCL_OK) { - return TCL_ERROR; - } - stopLine = TkBTreeLineIndex(stopIndex.linePtr); - if (!backwards && (stopLine == numLines)) { - stopLine = numLines-1; - } - searchWholeText = 0; - } else { - stopLine = 0; - searchWholeText = 1; - } - - /* - * Scan through all of the lines of the text circularly, starting - * at the given index. - */ - - matchLength = patLength = 0; /* Only needed to prevent compiler - * warnings. */ - if (exact) { - patLength = strlen(pattern); - } else { - regexp = Tcl_RegExpCompile(interp, pattern); - if (regexp == NULL) { - return TCL_ERROR; - } - } - lineNum = startingLine; - code = TCL_OK; - Tcl_DStringInit(&line); - for (passes = 0; passes < 2; ) { - if (lineNum >= numLines) { - /* - * Don't search the dummy last line of the text. - */ - - goto nextLine; - } - - /* - * Extract the text from the line. If we're doing regular - * expression matching, drop the newline from the line, so - * that "$" can be used to match the end of the line. - */ - - linePtr = TkBTreeFindLine(textPtr->tree, lineNum); - for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { - continue; - } - Tcl_DStringAppend(&line, segPtr->body.chars, segPtr->size); - } - if (!exact) { - Tcl_DStringSetLength(&line, Tcl_DStringLength(&line)-1); - } - startOfLine = Tcl_DStringValue(&line); - - /* - * If we're ignoring case, convert the line to lower case. - */ - - if (noCase) { - for (p = Tcl_DStringValue(&line); *p != 0; p++) { - if (isupper(UCHAR(*p))) { - *p = tolower(UCHAR(*p)); - } - } - } - - /* - * Check for matches within the current line. If so, and if we're - * searching backwards, repeat the search to find the last match - * in the line. - */ - - matchChar = -1; - firstChar = 0; - lastChar = INT_MAX; - if (lineNum == startingLine) { - int indexInDString; - - /* - * The starting line is tricky: the first time we see it - * we check one part of the line, and the second pass through - * we check the other part of the line. We have to be very - * careful here because there could be embedded windows or - * other things that are not in the extracted line. Rescan - * the original line to compute the index in it of the first - * character. - */ - - indexInDString = startingChar; - for (segPtr = linePtr->segPtr, leftToScan = startingChar; - leftToScan > 0; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { - indexInDString -= segPtr->size; - } - leftToScan -= segPtr->size; - } - - passes++; - if ((passes == 1) ^ backwards) { - /* - * Only use the last part of the line. - */ - - firstChar = indexInDString; - if (firstChar >= Tcl_DStringLength(&line)) { - goto nextLine; - } - } else { - /* - * Use only the first part of the line. - */ - - lastChar = indexInDString; - } - } - do { - int thisLength; - if (exact) { - p = strstr(startOfLine + firstChar, pattern); - if (p == NULL) { - break; - } - i = p - startOfLine; - thisLength = patLength; - } else { - char *start, *end; - int match; - - match = Tcl_RegExpExec(interp, regexp, - startOfLine + firstChar, startOfLine); - if (match < 0) { - code = TCL_ERROR; - goto done; - } - if (!match) { - break; - } - Tcl_RegExpRange(regexp, 0, &start, &end); - i = start - startOfLine; - thisLength = end - start; - } - if (i >= lastChar) { - break; - } - matchChar = i; - matchLength = thisLength; - firstChar = matchChar+1; - } while (backwards); - - /* - * If we found a match then we're done. Make sure that - * the match occurred before the stopping index, if one was - * specified. - */ - - if (matchChar >= 0) { - /* - * The index information returned by the regular expression - * parser only considers textual information: it doesn't - * account for embedded windows or any other non-textual info. - * Scan through the line's segments again to adjust both - * matchChar and matchCount. - */ - - for (segPtr = linePtr->segPtr, leftToScan = matchChar; - leftToScan >= 0; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { - matchChar += segPtr->size; - continue; - } - leftToScan -= segPtr->size; - } - for (leftToScan += matchLength; leftToScan > 0; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { - matchLength += segPtr->size; - continue; - } - leftToScan -= segPtr->size; - } - TkTextMakeIndex(textPtr->tree, lineNum, matchChar, &index); - if (!searchWholeText) { - if (!backwards && (TkTextIndexCmp(&index, &stopIndex) >= 0)) { - goto done; - } - if (backwards && (TkTextIndexCmp(&index, &stopIndex) < 0)) { - goto done; - } - } - if (varName != NULL) { - sprintf(buffer, "%d", matchLength); - if (Tcl_SetVar(interp, varName, buffer, TCL_LEAVE_ERR_MSG) - == NULL) { - code = TCL_ERROR; - goto done; - } - } - TkTextPrintIndex(&index, interp->result); - goto done; - } - - /* - * Go to the next (or previous) line; - */ - - nextLine: - if (backwards) { - lineNum--; - if (!searchWholeText) { - if (lineNum < stopLine) { - break; - } - } else if (lineNum < 0) { - lineNum = numLines-1; - } - } else { - lineNum++; - if (!searchWholeText) { - if (lineNum > stopLine) { - break; - } - } else if (lineNum >= numLines) { - lineNum = 0; - } - } - Tcl_DStringSetLength(&line, 0); - } - done: - Tcl_DStringFree(&line); - if (noCase) { - Tcl_DStringFree(&patDString); - } - return code; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextGetTabs -- - * - * Parses a string description of a set of tab stops. - * - * Results: - * The return value is a pointer to a malloc'ed structure holding - * parsed information about the tab stops. If an error occurred - * then the return value is NULL and an error message is left in - * interp->result. - * - * Side effects: - * Memory is allocated for the structure that is returned. It is - * up to the caller to free this structure when it is no longer - * needed. - * - *---------------------------------------------------------------------- - */ - -TkTextTabArray * -TkTextGetTabs(interp, tkwin, string) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Window tkwin; /* Window in which the tabs will be - * used. */ - char *string; /* Description of the tab stops. See - * the text manual entry for details. */ -{ - int argc, i, count, c; - char **argv; - TkTextTabArray *tabArrayPtr; - TkTextTab *tabPtr; - - if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) { - return NULL; - } - - /* - * First find out how many entries we need to allocate in the - * tab array. - */ - - count = 0; - for (i = 0; i < argc; i++) { - c = argv[i][0]; - if ((c != 'l') && (c != 'r') && (c != 'c') && (c != 'n')) { - count++; - } - } - - /* - * Parse the elements of the list one at a time to fill in the - * array. - */ - - tabArrayPtr = (TkTextTabArray *) ckalloc((unsigned) - (sizeof(TkTextTabArray) + (count-1)*sizeof(TkTextTab))); - tabArrayPtr->numTabs = 0; - for (i = 0, tabPtr = &tabArrayPtr->tabs[0]; i < argc; i++, tabPtr++) { - if (Tk_GetPixels(interp, tkwin, argv[i], &tabPtr->location) - != TCL_OK) { - goto error; - } - tabArrayPtr->numTabs++; - - /* - * See if there is an explicit alignment in the next list - * element. Otherwise just use "left". - */ - - tabPtr->alignment = LEFT; - if ((i+1) == argc) { - continue; - } - c = UCHAR(argv[i+1][0]); - if (!isalpha(c)) { - continue; - } - i += 1; - if ((c == 'l') && (strncmp(argv[i], "left", - strlen(argv[i])) == 0)) { - tabPtr->alignment = LEFT; - } else if ((c == 'r') && (strncmp(argv[i], "right", - strlen(argv[i])) == 0)) { - tabPtr->alignment = RIGHT; - } else if ((c == 'c') && (strncmp(argv[i], "center", - strlen(argv[i])) == 0)) { - tabPtr->alignment = CENTER; - } else if ((c == 'n') && (strncmp(argv[i], - "numeric", strlen(argv[i])) == 0)) { - tabPtr->alignment = NUMERIC; - } else { - Tcl_AppendResult(interp, "bad tab alignment \"", - argv[i], "\": must be left, right, center, or numeric", - (char *) NULL); - goto error; - } - } - ckfree((char *) argv); - return tabArrayPtr; - - error: - ckfree((char *) tabArrayPtr); - ckfree((char *) argv); - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TextDumpCmd -- - * - * Return information about the text, tags, marks, and embedded windows - * and images in a text widget. See the man page for the description - * of the text dump operation for all the details. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Memory is allocated for the result, if needed (standard Tcl result - * side effects). - * - *---------------------------------------------------------------------- - */ - -static int -TextDumpCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "dump". */ -{ - TkTextIndex index1, index2; - int arg; - int lineno; /* Current line number */ - int what = 0; /* bitfield to select segment types */ - int atEnd; /* True if dumping up to logical end */ - TkTextLine *linePtr; - char *command = NULL; /* Script callback to apply to segments */ -#define TK_DUMP_TEXT 0x1 -#define TK_DUMP_MARK 0x2 -#define TK_DUMP_TAG 0x4 -#define TK_DUMP_WIN 0x8 -#define TK_DUMP_IMG 0x10 -#define TK_DUMP_ALL (TK_DUMP_TEXT|TK_DUMP_MARK|TK_DUMP_TAG| \ - TK_DUMP_WIN|TK_DUMP_IMG) - - for (arg=2 ; argv[arg] != (char *) NULL ; arg++) { - size_t len; - if (argv[arg][0] != '-') { - break; - } - len = strlen(argv[arg]); - if (strncmp("-all", argv[arg], len) == 0) { - what = TK_DUMP_ALL; - } else if (strncmp("-text", argv[arg], len) == 0) { - what |= TK_DUMP_TEXT; - } else if (strncmp("-tag", argv[arg], len) == 0) { - what |= TK_DUMP_TAG; - } else if (strncmp("-mark", argv[arg], len) == 0) { - what |= TK_DUMP_MARK; - } else if (strncmp("-image", argv[arg], len) == 0) { - what |= TK_DUMP_IMG; - } else if (strncmp("-window", argv[arg], len) == 0) { - what |= TK_DUMP_WIN; - } else if (strncmp("-command", argv[arg], len) == 0) { - arg++; - if (arg >= argc) { - Tcl_AppendResult(interp, "Usage: ", argv[0], " dump ?-all -image -text -mark -tag -window? ?-command script? index ?index2?", NULL); - return TCL_ERROR; - } - command = argv[arg]; - } else { - Tcl_AppendResult(interp, "Usage: ", argv[0], " dump ?-all -image -text -mark -tag -window? ?-command script? index ?index2?", NULL); - return TCL_ERROR; - } - } - if (arg >= argc) { - Tcl_AppendResult(interp, "Usage: ", argv[0], " dump ?-all -image -text -mark -tag -window? ?-command script? index ?index2?", NULL); - return TCL_ERROR; - } - if (what == 0) { - what = TK_DUMP_ALL; - } - if (TkTextGetIndex(interp, textPtr, argv[arg], &index1) != TCL_OK) { - return TCL_ERROR; - } - lineno = TkBTreeLineIndex(index1.linePtr) + 1; - arg++; - atEnd = 0; - if (argc == arg) { - TkTextIndexForwChars(&index1, 1, &index2); - } else { - if (TkTextGetIndex(interp, textPtr, argv[arg], &index2) != TCL_OK) { - return TCL_ERROR; - } - if (strncmp(argv[arg], "end", strlen(argv[arg])) == 0) { - atEnd = 1; - } - } - if (TkTextIndexCmp(&index1, &index2) >= 0) { - return TCL_OK; - } - if (index1.linePtr == index2.linePtr) { - DumpLine(interp, textPtr, what, index1.linePtr, - index1.charIndex, index2.charIndex, lineno, command); - } else { - DumpLine(interp, textPtr, what, index1.linePtr, - index1.charIndex, 32000000, lineno, command); - linePtr = index1.linePtr; - while ((linePtr = TkBTreeNextLine(linePtr)) != (TkTextLine *)NULL) { - lineno++; - if (linePtr == index2.linePtr) { - break; - } - DumpLine(interp, textPtr, what, linePtr, 0, 32000000, - lineno, command); - } - DumpLine(interp, textPtr, what, index2.linePtr, 0, - index2.charIndex, lineno, command); - } - /* - * Special case to get the leftovers hiding at the end mark. - */ - if (atEnd) { - DumpLine(interp, textPtr, what & ~TK_DUMP_TEXT, index2.linePtr, - 0, 1, lineno, command); - - } - return TCL_OK; -} - -/* - * DumpLine - * Return information about a given text line from character - * position "start" up to, but not including, "end". - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None, but see DumpSegment. - */ -static void -DumpLine(interp, textPtr, what, linePtr, start, end, lineno, command) - Tcl_Interp *interp; - TkText *textPtr; - int what; /* bit flags to select segment types */ - TkTextLine *linePtr; /* The current line */ - int start, end; /* Character range to dump */ - int lineno; /* Line number for indices dump */ - char *command; /* Script to apply to the segment */ -{ - int offset; - TkTextSegment *segPtr; - /* - * Must loop through line looking at its segments. - * character - * toggleOn, toggleOff - * mark - * image - * window - */ - for (offset = 0, segPtr = linePtr->segPtr ; - (offset < end) && (segPtr != (TkTextSegment *)NULL) ; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - if ((what & TK_DUMP_TEXT) && (segPtr->typePtr == &tkTextCharType) && - (offset + segPtr->size > start)) { - char savedChar; /* Last char used in the seg */ - int last = segPtr->size; /* Index of savedChar */ - int first = 0; /* Index of first char in seg */ - if (offset + segPtr->size > end) { - last = end - offset; - } - if (start > offset) { - first = start - offset; - } - savedChar = segPtr->body.chars[last]; - segPtr->body.chars[last] = '\0'; - DumpSegment(interp, "text", segPtr->body.chars + first, - command, lineno, offset + first, what); - segPtr->body.chars[last] = savedChar; - } else if ((offset >= start)) { - if ((what & TK_DUMP_MARK) && (segPtr->typePtr->name[0] == 'm')) { - TkTextMark *markPtr = (TkTextMark *)&segPtr->body; - char *name = Tcl_GetHashKey(&textPtr->markTable, markPtr->hPtr); - DumpSegment(interp, "mark", name, - command, lineno, offset, what); - } else if ((what & TK_DUMP_TAG) && - (segPtr->typePtr == &tkTextToggleOnType)) { - DumpSegment(interp, "tagon", - segPtr->body.toggle.tagPtr->name, - command, lineno, offset, what); - } else if ((what & TK_DUMP_TAG) && - (segPtr->typePtr == &tkTextToggleOffType)) { - DumpSegment(interp, "tagoff", - segPtr->body.toggle.tagPtr->name, - command, lineno, offset, what); - } else if ((what & TK_DUMP_IMG) && - (segPtr->typePtr->name[0] == 'i')) { - TkTextEmbImage *eiPtr = (TkTextEmbImage *)&segPtr->body; - char *name = (eiPtr->name == NULL) ? "" : eiPtr->name; - DumpSegment(interp, "image", name, - command, lineno, offset, what); - } else if ((what & TK_DUMP_WIN) && - (segPtr->typePtr->name[0] == 'w')) { - TkTextEmbWindow *ewPtr = (TkTextEmbWindow *)&segPtr->body; - char *pathname; - if (ewPtr->tkwin == (Tk_Window) NULL) { - pathname = ""; - } else { - pathname = Tk_PathName(ewPtr->tkwin); - } - DumpSegment(interp, "window", pathname, - command, lineno, offset, what); - } - } - } -} - -/* - * DumpSegment - * Either append information about the current segment to the result, - * or make a script callback with that information as arguments. - * - * Results: - * None - * - * Side effects: - * Either evals the callback or appends elements to the result string. - */ -static int -DumpSegment(interp, key, value, command, lineno, offset, what) - Tcl_Interp *interp; - char *key; /* Segment type key */ - char *value; /* Segment value */ - char *command; /* Script callback */ - int lineno; /* Line number for indices dump */ - int offset; /* Character position */ - int what; /* Look for TK_DUMP_INDEX bit */ -{ - char buffer[30]; - sprintf(buffer, "%d.%d", lineno, offset); - if (command == (char *) NULL) { - Tcl_AppendElement(interp, key); - Tcl_AppendElement(interp, value); - Tcl_AppendElement(interp, buffer); - return TCL_OK; - } else { - char *argv[4]; - char *list; - int result; - argv[0] = key; - argv[1] = value; - argv[2] = buffer; - argv[3] = (char *) NULL; - list = Tcl_Merge(3, argv); - result = Tcl_VarEval(interp, command, " ", list, (char *) NULL); - ckfree(list); - return result; - } -} - diff --git a/generic/tkText.h b/generic/tkText.h deleted file mode 100644 index ad30c99..0000000 --- a/generic/tkText.h +++ /dev/null @@ -1,848 +0,0 @@ -/* - * tkText.h -- - * - * Declarations shared among the files that implement text - * widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkText.h,v 1.2 1998/09/14 18:23:18 stanton Exp $ - */ - -#ifndef _TKTEXT -#define _TKTEXT - -#ifndef _TK -#include "tk.h" -#endif - -/* - * Opaque types for structures whose guts are only needed by a single - * file: - */ - -typedef struct TkTextBTree *TkTextBTree; - -/* - * The data structure below defines a single line of text (from newline - * to newline, not necessarily what appears on one line of the screen). - */ - -typedef struct TkTextLine { - struct Node *parentPtr; /* Pointer to parent node containing - * line. */ - struct TkTextLine *nextPtr; /* Next in linked list of lines with - * same parent node in B-tree. NULL - * means end of list. */ - struct TkTextSegment *segPtr; /* First in ordered list of segments - * that make up the line. */ -} TkTextLine; - -/* - * ----------------------------------------------------------------------- - * Segments: each line is divided into one or more segments, where each - * segment is one of several things, such as a group of characters, a - * tag toggle, a mark, or an embedded widget. Each segment starts with - * a standard header followed by a body that varies from type to type. - * ----------------------------------------------------------------------- - */ - -/* - * The data structure below defines the body of a segment that represents - * a tag toggle. There is one of these structures at both the beginning - * and end of each tagged range. - */ - -typedef struct TkTextToggle { - struct TkTextTag *tagPtr; /* Tag that starts or ends here. */ - int inNodeCounts; /* 1 means this toggle has been - * accounted for in node toggle - * counts; 0 means it hasn't, yet. */ -} TkTextToggle; - -/* - * The data structure below defines line segments that represent - * marks. There is one of these for each mark in the text. - */ - -typedef struct TkTextMark { - struct TkText *textPtr; /* Overall information about text - * widget. */ - TkTextLine *linePtr; /* Line structure that contains the - * segment. */ - Tcl_HashEntry *hPtr; /* Pointer to hash table entry for mark - * (in textPtr->markTable). */ -} TkTextMark; - -/* - * A structure of the following type holds information for each window - * embedded in a text widget. This information is only used by the - * file tkTextWind.c - */ - -typedef struct TkTextEmbWindow { - struct TkText *textPtr; /* Information about the overall text - * widget. */ - TkTextLine *linePtr; /* Line structure that contains this - * window. */ - Tk_Window tkwin; /* Window for this segment. NULL - * means that the window hasn't - * been created yet. */ - char *create; /* Script to create window on-demand. - * NULL means no such script. - * Malloc-ed. */ - int align; /* How to align window in vertical - * space. See definitions in - * tkTextWind.c. */ - int padX, padY; /* Padding to leave around each side - * of window, in pixels. */ - int stretch; /* Should window stretch to fill - * vertical space of line (except for - * pady)? 0 or 1. */ - int chunkCount; /* Number of display chunks that - * refer to this window. */ - int displayed; /* Non-zero means that the window - * has been displayed on the screen - * recently. */ -} TkTextEmbWindow; - -/* - * A structure of the following type holds information for each image - * embedded in a text widget. This information is only used by the - * file tkTextImage.c - */ - -typedef struct TkTextEmbImage { - struct TkText *textPtr; /* Information about the overall text - * widget. */ - TkTextLine *linePtr; /* Line structure that contains this - * image. */ - char *imageString; /* Name of the image for this segment */ - char *imageName; /* Name used by text widget to identify - * this image. May be unique-ified */ - char *name; /* Name used in the hash table. - * used by "image names" to identify - * this instance of the image */ - Tk_Image image; /* Image for this segment. NULL - * means that the image hasn't - * been created yet. */ - int align; /* How to align image in vertical - * space. See definitions in - * tkTextImage.c. */ - int padX, padY; /* Padding to leave around each side - * of image, in pixels. */ - int chunkCount; /* Number of display chunks that - * refer to this image. */ -} TkTextEmbImage; - -/* - * The data structure below defines line segments. - */ - -typedef struct TkTextSegment { - struct Tk_SegType *typePtr; /* Pointer to record describing - * segment's type. */ - struct TkTextSegment *nextPtr; /* Next in list of segments for this - * line, or NULL for end of list. */ - int size; /* Size of this segment (# of bytes - * of index space it occupies). */ - union { - char chars[4]; /* Characters that make up character - * info. Actual length varies to - * hold as many characters as needed.*/ - TkTextToggle toggle; /* Information about tag toggle. */ - TkTextMark mark; /* Information about mark. */ - TkTextEmbWindow ew; /* Information about embedded - * window. */ - TkTextEmbImage ei; /* Information about embedded - * image. */ - } body; -} TkTextSegment; - -/* - * Data structures of the type defined below are used during the - * execution of Tcl commands to keep track of various interesting - * places in a text. An index is only valid up until the next - * modification to the character structure of the b-tree so they - * can't be retained across Tcl commands. However, mods to marks - * or tags don't invalidate indices. - */ - -typedef struct TkTextIndex { - TkTextBTree tree; /* Tree containing desired position. */ - TkTextLine *linePtr; /* Pointer to line containing position - * of interest. */ - int charIndex; /* Index within line of desired - * character (0 means first one). */ -} TkTextIndex; - -/* - * Types for procedure pointers stored in TkTextDispChunk strutures: - */ - -typedef struct TkTextDispChunk TkTextDispChunk; - -typedef void Tk_ChunkDisplayProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int x, int y, - int height, int baseline, Display *display, - Drawable dst, int screenY)); -typedef void Tk_ChunkUndisplayProc _ANSI_ARGS_(( - struct TkText *textPtr, - TkTextDispChunk *chunkPtr)); -typedef int Tk_ChunkMeasureProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int x)); -typedef void Tk_ChunkBboxProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int index, int y, - int lineHeight, int baseline, int *xPtr, - int *yPtr, int *widthPtr, int *heightPtr)); - -/* - * The structure below represents a chunk of stuff that is displayed - * together on the screen. This structure is allocated and freed by - * generic display code but most of its fields are filled in by - * segment-type-specific code. - */ - -struct TkTextDispChunk { - /* - * The fields below are set by the type-independent code before - * calling the segment-type-specific layoutProc. They should not - * be modified by segment-type-specific code. - */ - - int x; /* X position of chunk, in pixels. - * This position is measured from the - * left edge of the logical line, - * not from the left edge of the - * window (i.e. it doesn't change - * under horizontal scrolling). */ - struct TkTextDispChunk *nextPtr; /* Next chunk in the display line - * or NULL for the end of the list. */ - struct TextStyle *stylePtr; /* Display information, known only - * to tkTextDisp.c. */ - - /* - * The fields below are set by the layoutProc that creates the - * chunk. - */ - - Tk_ChunkDisplayProc *displayProc; /* Procedure to invoke to draw this - * chunk on the display or an - * off-screen pixmap. */ - Tk_ChunkUndisplayProc *undisplayProc; - /* Procedure to invoke when segment - * ceases to be displayed on screen - * anymore. */ - Tk_ChunkMeasureProc *measureProc; /* Procedure to find character under - * a given x-location. */ - Tk_ChunkBboxProc *bboxProc; /* Procedure to find bounding box - * of character in chunk. */ - int numChars; /* Number of characters that will be - * displayed in the chunk. */ - int minAscent; /* Minimum space above the baseline - * needed by this chunk. */ - int minDescent; /* Minimum space below the baseline - * needed by this chunk. */ - int minHeight; /* Minimum total line height needed - * by this chunk. */ - int width; /* Width of this chunk, in pixels. - * Initially set by chunk-specific - * code, but may be increased to - * include tab or extra space at end - * of line. */ - int breakIndex; /* Index within chunk of last - * acceptable position for a line - * (break just before this character). - * <= 0 means don't break during or - * immediately after this chunk. */ - ClientData clientData; /* Additional information for use - * of displayProc and undisplayProc. */ -}; - -/* - * One data structure of the following type is used for each tag in a - * text widget. These structures are kept in textPtr->tagTable and - * referred to in other structures. - */ - -typedef struct TkTextTag { - char *name; /* Name of this tag. This field is actually - * a pointer to the key from the entry in - * textPtr->tagTable, so it needn't be freed - * explicitly. */ - int priority; /* Priority of this tag within widget. 0 - * means lowest priority. Exactly one tag - * has each integer value between 0 and - * numTags-1. */ - struct Node *tagRootPtr; /* Pointer into the B-Tree at the lowest - * node that completely dominates the ranges - * of text occupied by the tag. At this - * node there is no information about the - * tag. One or more children of the node - * do contain information about the tag. */ - int toggleCount; /* Total number of tag toggles */ - - /* - * Information for displaying text with this tag. The information - * belows acts as an override on information specified by lower-priority - * tags. If no value is specified, then the next-lower-priority tag - * on the text determins the value. The text widget itself provides - * defaults if no tag specifies an override. - */ - - Tk_3DBorder border; /* Used for drawing background. NULL means - * no value specified here. */ - char *bdString; /* -borderwidth option string (malloc-ed). - * NULL means option not specified. */ - int borderWidth; /* Width of 3-D border for background. */ - char *reliefString; /* -relief option string (malloc-ed). - * NULL means option not specified. */ - int relief; /* 3-D relief for background. */ - Pixmap bgStipple; /* Stipple bitmap for background. None - * means no value specified here. */ - XColor *fgColor; /* Foreground color for text. NULL means - * no value specified here. */ - Tk_Font tkfont; /* Font for displaying text. NULL means - * no value specified here. */ - Pixmap fgStipple; /* Stipple bitmap for text and other - * foreground stuff. None means no value - * specified here.*/ - char *justifyString; /* -justify option string (malloc-ed). - * NULL means option not specified. */ - Tk_Justify justify; /* How to justify text: TK_JUSTIFY_LEFT, - * TK_JUSTIFY_RIGHT, or TK_JUSTIFY_CENTER. - * Only valid if justifyString is non-NULL. */ - char *lMargin1String; /* -lmargin1 option string (malloc-ed). - * NULL means option not specified. */ - int lMargin1; /* Left margin for first display line of - * each text line, in pixels. Only valid - * if lMargin1String is non-NULL. */ - char *lMargin2String; /* -lmargin2 option string (malloc-ed). - * NULL means option not specified. */ - int lMargin2; /* Left margin for second and later display - * lines of each text line, in pixels. Only - * valid if lMargin2String is non-NULL. */ - char *offsetString; /* -offset option string (malloc-ed). - * NULL means option not specified. */ - int offset; /* Vertical offset of text's baseline from - * baseline of line. Used for superscripts - * and subscripts. Only valid if - * offsetString is non-NULL. */ - char *overstrikeString; /* -overstrike option string (malloc-ed). - * NULL means option not specified. */ - int overstrike; /* Non-zero means draw horizontal line through - * middle of text. Only valid if - * overstrikeString is non-NULL. */ - char *rMarginString; /* -rmargin option string (malloc-ed). - * NULL means option not specified. */ - int rMargin; /* Right margin for text, in pixels. Only - * valid if rMarginString is non-NULL. */ - char *spacing1String; /* -spacing1 option string (malloc-ed). - * NULL means option not specified. */ - int spacing1; /* Extra spacing above first display - * line for text line. Only valid if - * spacing1String is non-NULL. */ - char *spacing2String; /* -spacing2 option string (malloc-ed). - * NULL means option not specified. */ - int spacing2; /* Extra spacing between display - * lines for the same text line. Only valid - * if spacing2String is non-NULL. */ - char *spacing3String; /* -spacing2 option string (malloc-ed). - * NULL means option not specified. */ - int spacing3; /* Extra spacing below last display - * line for text line. Only valid if - * spacing3String is non-NULL. */ - char *tabString; /* -tabs option string (malloc-ed). - * NULL means option not specified. */ - struct TkTextTabArray *tabArrayPtr; - /* Info about tabs for tag (malloc-ed) - * or NULL. Corresponds to tabString. */ - char *underlineString; /* -underline option string (malloc-ed). - * NULL means option not specified. */ - int underline; /* Non-zero means draw underline underneath - * text. Only valid if underlineString is - * non-NULL. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * Must be tkTextCharUid, tkTextNoneUid, - * tkTextWordUid, or NULL to use wrapMode - * for whole widget. */ - int affectsDisplay; /* Non-zero means that this tag affects the - * way information is displayed on the screen - * (so need to redisplay if tag changes). */ -} TkTextTag; - -#define TK_TAG_AFFECTS_DISPLAY 0x1 -#define TK_TAG_UNDERLINE 0x2 -#define TK_TAG_JUSTIFY 0x4 -#define TK_TAG_OFFSET 0x10 - -/* - * The data structure below is used for searching a B-tree for transitions - * on a single tag (or for all tag transitions). No code outside of - * tkTextBTree.c should ever modify any of the fields in these structures, - * but it's OK to use them for read-only information. - */ - -typedef struct TkTextSearch { - TkTextIndex curIndex; /* Position of last tag transition - * returned by TkBTreeNextTag, or - * index of start of segment - * containing starting position for - * search if TkBTreeNextTag hasn't - * been called yet, or same as - * stopIndex if search is over. */ - TkTextSegment *segPtr; /* Actual tag segment returned by last - * call to TkBTreeNextTag, or NULL if - * TkBTreeNextTag hasn't returned - * anything yet. */ - TkTextSegment *nextPtr; /* Where to resume search in next - * call to TkBTreeNextTag. */ - TkTextSegment *lastPtr; /* Stop search before just before - * considering this segment. */ - TkTextTag *tagPtr; /* Tag to search for (or tag found, if - * allTags is non-zero). */ - int linesLeft; /* Lines left to search (including - * curIndex and stopIndex). When - * this becomes <= 0 the search is - * over. */ - int allTags; /* Non-zero means ignore tag check: - * search for transitions on all - * tags. */ -} TkTextSearch; - -/* - * The following data structure describes a single tab stop. - */ - -typedef enum {LEFT, RIGHT, CENTER, NUMERIC} TkTextTabAlign; - -typedef struct TkTextTab { - int location; /* Offset in pixels of this tab stop - * from the left margin (lmargin2) of - * the text. */ - TkTextTabAlign alignment; /* Where the tab stop appears relative - * to the text. */ -} TkTextTab; - -typedef struct TkTextTabArray { - int numTabs; /* Number of tab stops. */ - TkTextTab tabs[1]; /* Array of tabs. The actual size - * will be numTabs. THIS FIELD MUST - * BE THE LAST IN THE STRUCTURE. */ -} TkTextTabArray; - -/* - * A data structure of the following type is kept for each text widget that - * currently exists for this process: - */ - -typedef struct TkText { - Tk_Window tkwin; /* Window that embodies the text. NULL - * means that the window has been destroyed - * but the data structures haven't yet been - * cleaned up.*/ - Display *display; /* Display for widget. Needed, among other - * things, to allow resources to be freed - * even after tkwin has gone away. */ - Tcl_Interp *interp; /* Interpreter associated with widget. Used - * to delete widget command. */ - Tcl_Command widgetCmd; /* Token for text's widget command. */ - TkTextBTree tree; /* B-tree representation of text and tags for - * widget. */ - Tcl_HashTable tagTable; /* Hash table that maps from tag names to - * pointers to TkTextTag structures. */ - int numTags; /* Number of tags currently defined for - * widget; needed to keep track of - * priorities. */ - Tcl_HashTable markTable; /* Hash table that maps from mark names to - * pointers to mark segments. */ - Tcl_HashTable windowTable; /* Hash table that maps from window names - * to pointers to window segments. If a - * window segment doesn't yet have an - * associated window, there is no entry for - * it here. */ - Tcl_HashTable imageTable; /* Hash table that maps from image names - * to pointers to image segments. If an - * image segment doesn't yet have an - * associated image, there is no entry for - * it here. */ - Tk_Uid state; /* Normal or disabled. Text is read-only - * when disabled. */ - - /* - * Default information for displaying (may be overridden by tags - * applied to ranges of characters). - */ - - Tk_3DBorder border; /* Structure used to draw 3-D border and - * default background. */ - int borderWidth; /* Width of 3-D border to draw around entire - * widget. */ - int padX, padY; /* Padding between text and window border. */ - int relief; /* 3-d effect for border around entire - * widget: TK_RELIEF_RAISED etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. - * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - XColor *fgColor; /* Default foreground color for text. */ - Tk_Font tkfont; /* Default font for displaying text. */ - int charWidth; /* Width of average character in default - * font. */ - int spacing1; /* Default extra spacing above first display - * line for each text line. */ - int spacing2; /* Default extra spacing between display lines - * for the same text line. */ - int spacing3; /* Default extra spacing below last display - * line for each text line. */ - char *tabOptionString; /* Value of -tabs option string (malloc'ed). */ - TkTextTabArray *tabArrayPtr; - /* Information about tab stops (malloc'ed). - * NULL means perform default tabbing - * behavior. */ - - /* - * Additional information used for displaying: - */ - - Tk_Uid wrapMode; /* How to handle wrap-around. Must be - * tkTextCharUid, tkTextNoneUid, or - * tkTextWordUid. */ - int width, height; /* Desired dimensions for window, measured - * in characters. */ - int setGrid; /* Non-zero means pass gridding information - * to window manager. */ - int prevWidth, prevHeight; /* Last known dimensions of window; used to - * detect changes in size. */ - TkTextIndex topIndex; /* Identifies first character in top display - * line of window. */ - struct TextDInfo *dInfoPtr; /* Information maintained by tkTextDisp.c. */ - - /* - * Information related to selection. - */ - - TkTextTag *selTagPtr; /* Pointer to "sel" tag. Used to tell when - * a new selection has been made. */ - Tk_3DBorder selBorder; /* Border and background for selected - * characters. This is a copy of information - * in *cursorTagPtr, so it shouldn't be - * explicitly freed. */ - char *selBdString; /* Value of -selectborderwidth option, or NULL - * if not specified (malloc'ed). */ - XColor *selFgColorPtr; /* Foreground color for selected text. - * This is a copy of information in - * *cursorTagPtr, so it shouldn't be - * explicitly freed. */ - int exportSelection; /* Non-zero means tie "sel" tag to X - * selection. */ - TkTextIndex selIndex; /* Used during multi-pass selection retrievals. - * This index identifies the next character - * to be returned from the selection. */ - int abortSelections; /* Set to 1 whenever the text is modified - * in a way that interferes with selection - * retrieval: used to abort incremental - * selection retrievals. */ - int selOffset; /* Offset in selection corresponding to - * selLine and selCh. -1 means neither - * this information nor selIndex is of any - * use. */ - - /* - * Information related to insertion cursor: - */ - - TkTextSegment *insertMarkPtr; - /* Points to segment for "insert" mark. */ - Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion - * cursor. */ - int insertWidth; /* Total width of insert cursor. */ - int insertBorderWidth; /* Width of 3-D border around insert cursor. */ - int insertOnTime; /* Number of milliseconds cursor should spend - * in "on" state for each blink. */ - int insertOffTime; /* Number of milliseconds cursor should spend - * in "off" state for each blink. */ - Tcl_TimerToken insertBlinkHandler; - /* Timer handler used to blink cursor on and - * off. */ - - /* - * Information used for event bindings associated with tags: - */ - - Tk_BindingTable bindingTable; - /* Table of all bindings currently defined - * for this widget. NULL means that no - * bindings exist, so the table hasn't been - * created. Each "object" used for this - * table is the address of a tag. */ - TkTextSegment *currentMarkPtr; - /* Pointer to segment for "current" mark, - * or NULL if none. */ - XEvent pickEvent; /* The event from which the current character - * was chosen. Must be saved so that we - * can repick after modifications to the - * text. */ - int numCurTags; /* Number of tags associated with character - * at current mark. */ - TkTextTag **curTagArrayPtr; /* Pointer to array of tags for current - * mark, or NULL if none. */ - - /* - * Miscellaneous additional information: - */ - - char *takeFocus; /* Value of -takeFocus option; not used in - * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - char *xScrollCmd; /* Prefix of command to issue to update - * horizontal scrollbar when view changes. */ - char *yScrollCmd; /* Prefix of command to issue to update - * vertical scrollbar when view changes. */ - int flags; /* Miscellaneous flags; see below for - * definitions. */ -} TkText; - -/* - * Flag values for TkText records: - * - * GOT_SELECTION: Non-zero means we've already claimed the - * selection. - * INSERT_ON: Non-zero means insertion cursor should be - * displayed on screen. - * GOT_FOCUS: Non-zero means this window has the input - * focus. - * BUTTON_DOWN: 1 means that a mouse button is currently - * down; this is used to implement grabs - * for the duration of button presses. - * UPDATE_SCROLLBARS: Non-zero means scrollbar(s) should be updated - * during next redisplay operation. - */ - -#define GOT_SELECTION 1 -#define INSERT_ON 2 -#define GOT_FOCUS 4 -#define BUTTON_DOWN 8 -#define UPDATE_SCROLLBARS 0x10 -#define NEED_REPICK 0x20 - -/* - * Records of the following type define segment types in terms of - * a collection of procedures that may be called to manipulate - * segments of that type. - */ - -typedef TkTextSegment * Tk_SegSplitProc _ANSI_ARGS_(( - struct TkTextSegment *segPtr, int index)); -typedef int Tk_SegDeleteProc _ANSI_ARGS_(( - struct TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -typedef TkTextSegment * Tk_SegCleanupProc _ANSI_ARGS_(( - struct TkTextSegment *segPtr, TkTextLine *linePtr)); -typedef void Tk_SegLineChangeProc _ANSI_ARGS_(( - struct TkTextSegment *segPtr, TkTextLine *linePtr)); -typedef int Tk_SegLayoutProc _ANSI_ARGS_((struct TkText *textPtr, - struct TkTextIndex *indexPtr, TkTextSegment *segPtr, - int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, - struct TkTextDispChunk *chunkPtr)); -typedef void Tk_SegCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); - -typedef struct Tk_SegType { - char *name; /* Name of this kind of segment. */ - int leftGravity; /* If a segment has zero size (e.g. a - * mark or tag toggle), does it - * attach to character to its left - * or right? 1 means left, 0 means - * right. */ - Tk_SegSplitProc *splitProc; /* Procedure to split large segment - * into two smaller ones. */ - Tk_SegDeleteProc *deleteProc; /* Procedure to call to delete - * segment. */ - Tk_SegCleanupProc *cleanupProc; /* After any change to a line, this - * procedure is invoked for all - * segments left in the line to - * perform any cleanup they wish - * (e.g. joining neighboring - * segments). */ - Tk_SegLineChangeProc *lineChangeProc; - /* Invoked when a segment is about - * to be moved from its current line - * to an earlier line because of - * a deletion. The linePtr is that - * for the segment's old line. - * CleanupProc will be invoked after - * the deletion is finished. */ - Tk_SegLayoutProc *layoutProc; /* Returns size information when - * figuring out what to display in - * window. */ - Tk_SegCheckProc *checkProc; /* Called during consistency checks - * to check internal consistency of - * segment. */ -} Tk_SegType; - -/* - * The constant below is used to specify a line when what is really - * wanted is the entire text. For now, just use a very big number. - */ - -#define TK_END_OF_TEXT 1000000 - -/* - * The following definition specifies the maximum number of characters - * needed in a string to hold a position specifier. - */ - -#define TK_POS_CHARS 30 - -/* - * Declarations for variables shared among the text-related files: - */ - -extern int tkBTreeDebug; -extern int tkTextDebug; -extern Tk_SegType tkTextCharType; -extern Tk_Uid tkTextCharUid; -extern Tk_Uid tkTextDisabledUid; -extern Tk_SegType tkTextLeftMarkType; -extern Tk_Uid tkTextNoneUid; -extern Tk_Uid tkTextNormalUid; -extern Tk_SegType tkTextRightMarkType; -extern Tk_SegType tkTextToggleOnType; -extern Tk_SegType tkTextToggleOffType; -extern Tk_Uid tkTextWordUid; - -/* - * Declarations for procedures that are used by the text-related files - * but shouldn't be used anywhere else in Tk (or by Tk clients): - */ - -extern int TkBTreeCharTagged _ANSI_ARGS_((TkTextIndex *indexPtr, - TkTextTag *tagPtr)); -extern void TkBTreeCheck _ANSI_ARGS_((TkTextBTree tree)); -extern int TkBTreeCharsInLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern TkTextBTree TkBTreeCreate _ANSI_ARGS_((TkText *textPtr)); -extern void TkBTreeDestroy _ANSI_ARGS_((TkTextBTree tree)); -extern void TkBTreeDeleteChars _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr)); -extern TkTextLine * TkBTreeFindLine _ANSI_ARGS_((TkTextBTree tree, - int line)); -extern TkTextTag ** TkBTreeGetTags _ANSI_ARGS_((TkTextIndex *indexPtr, - int *numTagsPtr)); -extern void TkBTreeInsertChars _ANSI_ARGS_((TkTextIndex *indexPtr, - char *string)); -extern int TkBTreeLineIndex _ANSI_ARGS_((TkTextLine *linePtr)); -extern void TkBTreeLinkSegment _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextIndex *indexPtr)); -extern TkTextLine * TkBTreeNextLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern int TkBTreeNextTag _ANSI_ARGS_((TkTextSearch *searchPtr)); -extern int TkBTreeNumLines _ANSI_ARGS_((TkTextBTree tree)); -extern TkTextLine * TkBTreePreviousLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern int TkBTreePrevTag _ANSI_ARGS_((TkTextSearch *searchPtr)); -extern void TkBTreeStartSearch _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr, TkTextTag *tagPtr, - TkTextSearch *searchPtr)); -extern void TkBTreeStartSearchBack _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr, TkTextTag *tagPtr, - TkTextSearch *searchPtr)); -extern void TkBTreeTag _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr, TkTextTag *tagPtr, - int add)); -extern void TkBTreeUnlinkSegment _ANSI_ARGS_((TkTextBTree tree, - TkTextSegment *segPtr, TkTextLine *linePtr)); -extern void TkTextBindProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -extern void TkTextChanged _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *index1Ptr, TkTextIndex *index2Ptr)); -extern int TkTextCharBbox _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, int *xPtr, int *yPtr, - int *widthPtr, int *heightPtr)); -extern int TkTextCharLayoutProc _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, TkTextSegment *segPtr, - int offset, int maxX, int maxChars, int noBreakYet, - Tk_Uid wrapMode, TkTextDispChunk *chunkPtr)); -extern void TkTextCreateDInfo _ANSI_ARGS_((TkText *textPtr)); -extern int TkTextDLineInfo _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, int *xPtr, int *yPtr, - int *widthPtr, int *heightPtr, int *basePtr)); -extern TkTextTag * TkTextCreateTag _ANSI_ARGS_((TkText *textPtr, - char *tagName)); -extern void TkTextFreeDInfo _ANSI_ARGS_((TkText *textPtr)); -extern void TkTextFreeTag _ANSI_ARGS_((TkText *textPtr, - TkTextTag *tagPtr)); -extern int TkTextGetIndex _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, char *string, - TkTextIndex *indexPtr)); -extern TkTextTabArray * TkTextGetTabs _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string)); -extern void TkTextIndexBackChars _ANSI_ARGS_((TkTextIndex *srcPtr, - int count, TkTextIndex *dstPtr)); -extern int TkTextIndexCmp _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr)); -extern void TkTextIndexForwChars _ANSI_ARGS_((TkTextIndex *srcPtr, - int count, TkTextIndex *dstPtr)); -extern TkTextSegment * TkTextIndexToSeg _ANSI_ARGS_((TkTextIndex *indexPtr, - int *offsetPtr)); -extern void TkTextInsertDisplayProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int x, int y, int height, - int baseline, Display *display, Drawable dst, - int screenY)); -extern void TkTextLostSelection _ANSI_ARGS_(( - ClientData clientData)); -extern TkTextIndex * TkTextMakeIndex _ANSI_ARGS_((TkTextBTree tree, - int lineIndex, int charIndex, - TkTextIndex *indexPtr)); -extern int TkTextMarkCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextMarkNameToIndex _ANSI_ARGS_((TkText *textPtr, - char *name, TkTextIndex *indexPtr)); -extern void TkTextMarkSegToIndex _ANSI_ARGS_((TkText *textPtr, - TkTextSegment *markPtr, TkTextIndex *indexPtr)); -extern void TkTextEventuallyRepick _ANSI_ARGS_((TkText *textPtr)); -extern void TkTextPickCurrent _ANSI_ARGS_((TkText *textPtr, - XEvent *eventPtr)); -extern void TkTextPixelIndex _ANSI_ARGS_((TkText *textPtr, - int x, int y, TkTextIndex *indexPtr)); -extern void TkTextPrintIndex _ANSI_ARGS_((TkTextIndex *indexPtr, - char *string)); -extern void TkTextRedrawRegion _ANSI_ARGS_((TkText *textPtr, - int x, int y, int width, int height)); -extern void TkTextRedrawTag _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, - TkTextTag *tagPtr, int withTag)); -extern void TkTextRelayoutWindow _ANSI_ARGS_((TkText *textPtr)); -extern int TkTextScanCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextSeeCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextSegToOffset _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -extern TkTextSegment * TkTextSetMark _ANSI_ARGS_((TkText *textPtr, char *name, - TkTextIndex *indexPtr)); -extern void TkTextSetYView _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, int pickPlace)); -extern int TkTextTagCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextImageCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextImageIndex _ANSI_ARGS_((TkText *textPtr, - char *name, TkTextIndex *indexPtr)); -extern int TkTextWindowCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextWindowIndex _ANSI_ARGS_((TkText *textPtr, - char *name, TkTextIndex *indexPtr)); -extern int TkTextXviewCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextYviewCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int argc, char **argv)); - -#endif /* _TKTEXT */ diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c deleted file mode 100644 index 44b021f..0000000 --- a/generic/tkTextBTree.c +++ /dev/null @@ -1,3594 +0,0 @@ -/* - * tkTextBTree.c -- - * - * This file contains code that manages the B-tree representation - * of text for Tk's text widget and implements character and - * toggle segment types. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextBTree.c,v 1.2 1998/09/14 18:23:18 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" -#include "tkText.h" - -/* - * The data structure below keeps summary information about one tag as part - * of the tag information in a node. - */ - -typedef struct Summary { - TkTextTag *tagPtr; /* Handle for tag. */ - int toggleCount; /* Number of transitions into or - * out of this tag that occur in - * the subtree rooted at this node. */ - struct Summary *nextPtr; /* Next in list of all tags for same - * node, or NULL if at end of list. */ -} Summary; - -/* - * The data structure below defines a node in the B-tree. - */ - -typedef struct Node { - struct Node *parentPtr; /* Pointer to parent node, or NULL if - * this is the root. */ - struct Node *nextPtr; /* Next in list of siblings with the - * same parent node, or NULL for end - * of list. */ - Summary *summaryPtr; /* First in malloc-ed list of info - * about tags in this subtree (NULL if - * no tag info in the subtree). */ - int level; /* Level of this node in the B-tree. - * 0 refers to the bottom of the tree - * (children are lines, not nodes). */ - union { /* First in linked list of children. */ - struct Node *nodePtr; /* Used if level > 0. */ - TkTextLine *linePtr; /* Used if level == 0. */ - } children; - int numChildren; /* Number of children of this node. */ - int numLines; /* Total number of lines (leaves) in - * the subtree rooted here. */ -} Node; - -/* - * Upper and lower bounds on how many children a node may have: - * rebalance when either of these limits is exceeded. MAX_CHILDREN - * should be twice MIN_CHILDREN and MIN_CHILDREN must be >= 2. - */ - -#define MAX_CHILDREN 12 -#define MIN_CHILDREN 6 - -/* - * The data structure below defines an entire B-tree. - */ - -typedef struct BTree { - Node *rootPtr; /* Pointer to root of B-tree. */ - TkText *textPtr; /* Used to find tagTable in consistency - * checking code */ -} BTree; - -/* - * The structure below is used to pass information between - * TkBTreeGetTags and IncCount: - */ - -typedef struct TagInfo { - int numTags; /* Number of tags for which there - * is currently information in - * tags and counts. */ - int arraySize; /* Number of entries allocated for - * tags and counts. */ - TkTextTag **tagPtrs; /* Array of tags seen so far. - * Malloc-ed. */ - int *counts; /* Toggle count (so far) for each - * entry in tags. Malloc-ed. */ -} TagInfo; - -/* - * Variable that indicates whether to enable consistency checks for - * debugging. - */ - -int tkBTreeDebug = 0; - -/* - * Macros that determine how much space to allocate for new segments: - */ - -#define CSEG_SIZE(chars) ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + 1 + (chars))) -#define TSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + sizeof(TkTextToggle))) - -/* - * Forward declarations for procedures defined in this file: - */ - -static void ChangeNodeToggleCount _ANSI_ARGS_((Node *nodePtr, - TkTextTag *tagPtr, int delta)); -static void CharCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static int CharDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -static TkTextSegment * CharCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static TkTextSegment * CharSplitProc _ANSI_ARGS_((TkTextSegment *segPtr, - int index)); -static void CheckNodeConsistency _ANSI_ARGS_((Node *nodePtr)); -static void CleanupLine _ANSI_ARGS_((TkTextLine *linePtr)); -static void DeleteSummaries _ANSI_ARGS_((Summary *tagPtr)); -static void DestroyNode _ANSI_ARGS_((Node *nodePtr)); -static TkTextSegment * FindTagEnd _ANSI_ARGS_((TkTextBTree tree, - TkTextTag *tagPtr, TkTextIndex *indexPtr)); -static void IncCount _ANSI_ARGS_((TkTextTag *tagPtr, int inc, - TagInfo *tagInfoPtr)); -static void Rebalance _ANSI_ARGS_((BTree *treePtr, Node *nodePtr)); -static void RecomputeNodeCounts _ANSI_ARGS_((Node *nodePtr)); -static TkTextSegment * SplitSeg _ANSI_ARGS_((TkTextIndex *indexPtr)); -static void ToggleCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static TkTextSegment * ToggleCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static int ToggleDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -static void ToggleLineChangeProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static TkTextSegment * FindTagStart _ANSI_ARGS_((TkTextBTree tree, - TkTextTag *tagPtr, TkTextIndex *indexPtr)); - -/* - * Type record for character segments: - */ - -Tk_SegType tkTextCharType = { - "character", /* name */ - 0, /* leftGravity */ - CharSplitProc, /* splitProc */ - CharDeleteProc, /* deleteProc */ - CharCleanupProc, /* cleanupProc */ - (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */ - TkTextCharLayoutProc, /* layoutProc */ - CharCheckProc /* checkProc */ -}; - -/* - * Type record for segments marking the beginning of a tagged - * range: - */ - -Tk_SegType tkTextToggleOnType = { - "toggleOn", /* name */ - 0, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - ToggleDeleteProc, /* deleteProc */ - ToggleCleanupProc, /* cleanupProc */ - ToggleLineChangeProc, /* lineChangeProc */ - (Tk_SegLayoutProc *) NULL, /* layoutProc */ - ToggleCheckProc /* checkProc */ -}; - -/* - * Type record for segments marking the end of a tagged - * range: - */ - -Tk_SegType tkTextToggleOffType = { - "toggleOff", /* name */ - 1, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - ToggleDeleteProc, /* deleteProc */ - ToggleCleanupProc, /* cleanupProc */ - ToggleLineChangeProc, /* lineChangeProc */ - (Tk_SegLayoutProc *) NULL, /* layoutProc */ - ToggleCheckProc /* checkProc */ -}; - -/* - *---------------------------------------------------------------------- - * - * TkBTreeCreate -- - * - * This procedure is called to create a new text B-tree. - * - * Results: - * The return value is a pointer to a new B-tree containing - * one line with nothing but a newline character. - * - * Side effects: - * Memory is allocated and initialized. - * - *---------------------------------------------------------------------- - */ - -TkTextBTree -TkBTreeCreate(textPtr) - TkText *textPtr; -{ - register BTree *treePtr; - register Node *rootPtr; - register TkTextLine *linePtr, *linePtr2; - register TkTextSegment *segPtr; - - /* - * The tree will initially have two empty lines. The second line - * isn't actually part of the tree's contents, but its presence - * makes several operations easier. The tree will have one node, - * which is also the root of the tree. - */ - - rootPtr = (Node *) ckalloc(sizeof(Node)); - linePtr = (TkTextLine *) ckalloc(sizeof(TkTextLine)); - linePtr2 = (TkTextLine *) ckalloc(sizeof(TkTextLine)); - rootPtr->parentPtr = NULL; - rootPtr->nextPtr = NULL; - rootPtr->summaryPtr = NULL; - rootPtr->level = 0; - rootPtr->children.linePtr = linePtr; - rootPtr->numChildren = 2; - rootPtr->numLines = 2; - - linePtr->parentPtr = rootPtr; - linePtr->nextPtr = linePtr2; - segPtr = (TkTextSegment *) ckalloc(CSEG_SIZE(1)); - linePtr->segPtr = segPtr; - segPtr->typePtr = &tkTextCharType; - segPtr->nextPtr = NULL; - segPtr->size = 1; - segPtr->body.chars[0] = '\n'; - segPtr->body.chars[1] = 0; - - linePtr2->parentPtr = rootPtr; - linePtr2->nextPtr = NULL; - segPtr = (TkTextSegment *) ckalloc(CSEG_SIZE(1)); - linePtr2->segPtr = segPtr; - segPtr->typePtr = &tkTextCharType; - segPtr->nextPtr = NULL; - segPtr->size = 1; - segPtr->body.chars[0] = '\n'; - segPtr->body.chars[1] = 0; - - treePtr = (BTree *) ckalloc(sizeof(BTree)); - treePtr->rootPtr = rootPtr; - treePtr->textPtr = textPtr; - - return (TkTextBTree) treePtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeDestroy -- - * - * Delete a B-tree, recycling all of the storage it contains. - * - * Results: - * The tree given by treePtr is deleted. TreePtr should never - * again be used. - * - * Side effects: - * Memory is freed. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeDestroy(tree) - TkTextBTree tree; /* Pointer to tree to delete. */ -{ - BTree *treePtr = (BTree *) tree; - - DestroyNode(treePtr->rootPtr); - ckfree((char *) treePtr); -} - -/* - *---------------------------------------------------------------------- - * - * DestroyNode -- - * - * This is a recursive utility procedure used during the deletion - * of a B-tree. - * - * Results: - * None. - * - * Side effects: - * All the storage for nodePtr and its descendants is freed. - * - *---------------------------------------------------------------------- - */ - -static void -DestroyNode(nodePtr) - register Node *nodePtr; -{ - if (nodePtr->level == 0) { - TkTextLine *linePtr; - TkTextSegment *segPtr; - - while (nodePtr->children.linePtr != NULL) { - linePtr = nodePtr->children.linePtr; - nodePtr->children.linePtr = linePtr->nextPtr; - while (linePtr->segPtr != NULL) { - segPtr = linePtr->segPtr; - linePtr->segPtr = segPtr->nextPtr; - (*segPtr->typePtr->deleteProc)(segPtr, linePtr, 1); - } - ckfree((char *) linePtr); - } - } else { - register Node *childPtr; - - while (nodePtr->children.nodePtr != NULL) { - childPtr = nodePtr->children.nodePtr; - nodePtr->children.nodePtr = childPtr->nextPtr; - DestroyNode(childPtr); - } - } - DeleteSummaries(nodePtr->summaryPtr); - ckfree((char *) nodePtr); -} - -/* - *---------------------------------------------------------------------- - * - * DeleteSummaries -- - * - * Free up all of the memory in a list of tag summaries associated - * with a node. - * - * Results: - * None. - * - * Side effects: - * Storage is released. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteSummaries(summaryPtr) - register Summary *summaryPtr; /* First in list of node's tag - * summaries. */ -{ - register Summary *nextPtr; - while (summaryPtr != NULL) { - nextPtr = summaryPtr->nextPtr; - ckfree((char *) summaryPtr); - summaryPtr = nextPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeInsertChars -- - * - * Insert characters at a given position in a B-tree. - * - * Results: - * None. - * - * Side effects: - * Characters are added to the B-tree at the given position. - * If the string contains newlines, new lines will be added, - * which could cause the structure of the B-tree to change. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeInsertChars(indexPtr, string) - register TkTextIndex *indexPtr; /* Indicates where to insert text. - * When the procedure returns, this - * index is no longer valid because - * of changes to the segment - * structure. */ - char *string; /* Pointer to bytes to insert (may - * contain newlines, must be null- - * terminated). */ -{ - register Node *nodePtr; - register TkTextSegment *prevPtr; /* The segment just before the first - * new segment (NULL means new segment - * is at beginning of line). */ - TkTextSegment *curPtr; /* Current segment; new characters - * are inserted just after this one. - * NULL means insert at beginning of - * line. */ - TkTextLine *linePtr; /* Current line (new segments are - * added to this line). */ - register TkTextSegment *segPtr; - TkTextLine *newLinePtr; - int chunkSize; /* # characters in current chunk. */ - register char *eol; /* Pointer to character just after last - * one in current chunk. */ - int changeToLineCount; /* Counts change to total number of - * lines in file. */ - - prevPtr = SplitSeg(indexPtr); - linePtr = indexPtr->linePtr; - curPtr = prevPtr; - - /* - * Chop the string up into lines and create a new segment for - * each line, plus a new line for the leftovers from the - * previous line. - */ - - changeToLineCount = 0; - while (*string != 0) { - for (eol = string; *eol != 0; eol++) { - if (*eol == '\n') { - eol++; - break; - } - } - chunkSize = eol-string; - segPtr = (TkTextSegment *) ckalloc(CSEG_SIZE(chunkSize)); - segPtr->typePtr = &tkTextCharType; - if (curPtr == NULL) { - segPtr->nextPtr = linePtr->segPtr; - linePtr->segPtr = segPtr; - } else { - segPtr->nextPtr = curPtr->nextPtr; - curPtr->nextPtr = segPtr; - } - segPtr->size = chunkSize; - strncpy(segPtr->body.chars, string, (size_t) chunkSize); - segPtr->body.chars[chunkSize] = 0; - - if (eol[-1] != '\n') { - break; - } - - /* - * The chunk ended with a newline, so create a new TkTextLine - * and move the remainder of the old line to it. - */ - - newLinePtr = (TkTextLine *) ckalloc(sizeof(TkTextLine)); - newLinePtr->parentPtr = linePtr->parentPtr; - newLinePtr->nextPtr = linePtr->nextPtr; - linePtr->nextPtr = newLinePtr; - newLinePtr->segPtr = segPtr->nextPtr; - segPtr->nextPtr = NULL; - linePtr = newLinePtr; - curPtr = NULL; - changeToLineCount++; - - string = eol; - } - - /* - * Cleanup the starting line for the insertion, plus the ending - * line if it's different. - */ - - CleanupLine(indexPtr->linePtr); - if (linePtr != indexPtr->linePtr) { - CleanupLine(linePtr); - } - - /* - * Increment the line counts in all the parent nodes of the insertion - * point, then rebalance the tree if necessary. - */ - - for (nodePtr = linePtr->parentPtr ; nodePtr != NULL; - nodePtr = nodePtr->parentPtr) { - nodePtr->numLines += changeToLineCount; - } - nodePtr = linePtr->parentPtr; - nodePtr->numChildren += changeToLineCount; - if (nodePtr->numChildren > MAX_CHILDREN) { - Rebalance((BTree *) indexPtr->tree, nodePtr); - } - - if (tkBTreeDebug) { - TkBTreeCheck(indexPtr->tree); - } -} - -/* - *-------------------------------------------------------------- - * - * SplitSeg -- - * - * This procedure is called before adding or deleting - * segments. It does three things: (a) it finds the segment - * containing indexPtr; (b) if there are several such - * segments (because some segments have zero length) then - * it picks the first segment that does not have left - * gravity; (c) if the index refers to the middle of - * a segment then it splits the segment so that the - * index now refers to the beginning of a segment. - * - * Results: - * The return value is a pointer to the segment just - * before the segment corresponding to indexPtr (as - * described above). If the segment corresponding to - * indexPtr is the first in its line then the return - * value is NULL. - * - * Side effects: - * The segment referred to by indexPtr is split unless - * indexPtr refers to its first character. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -SplitSeg(indexPtr) - TkTextIndex *indexPtr; /* Index identifying position - * at which to split a segment. */ -{ - TkTextSegment *prevPtr, *segPtr; - int count; - - for (count = indexPtr->charIndex, prevPtr = NULL, - segPtr = indexPtr->linePtr->segPtr; segPtr != NULL; - count -= segPtr->size, prevPtr = segPtr, segPtr = segPtr->nextPtr) { - if (segPtr->size > count) { - if (count == 0) { - return prevPtr; - } - segPtr = (*segPtr->typePtr->splitProc)(segPtr, count); - if (prevPtr == NULL) { - indexPtr->linePtr->segPtr = segPtr; - } else { - prevPtr->nextPtr = segPtr; - } - return segPtr; - } else if ((segPtr->size == 0) && (count == 0) - && !segPtr->typePtr->leftGravity) { - return prevPtr; - } - } - panic("SplitSeg reached end of line!"); - return NULL; -} - -/* - *-------------------------------------------------------------- - * - * CleanupLine -- - * - * This procedure is called after modifications have been - * made to a line. It scans over all of the segments in - * the line, giving each a chance to clean itself up, e.g. - * by merging with the following segments, updating internal - * information, etc. - * - * Results: - * None. - * - * Side effects: - * Depends on what the segment-specific cleanup procedures do. - * - *-------------------------------------------------------------- - */ - -static void -CleanupLine(linePtr) - TkTextLine *linePtr; /* Line to be cleaned up. */ -{ - TkTextSegment *segPtr, **prevPtrPtr; - int anyChanges; - - /* - * Make a pass over all of the segments in the line, giving each - * a chance to clean itself up. This could potentially change - * the structure of the line, e.g. by merging two segments - * together or having two segments cancel themselves; if so, - * then repeat the whole process again, since the first structure - * change might make other structure changes possible. Repeat - * until eventually there are no changes. - */ - - while (1) { - anyChanges = 0; - for (prevPtrPtr = &linePtr->segPtr, segPtr = *prevPtrPtr; - segPtr != NULL; - prevPtrPtr = &(*prevPtrPtr)->nextPtr, segPtr = *prevPtrPtr) { - if (segPtr->typePtr->cleanupProc != NULL) { - *prevPtrPtr = (*segPtr->typePtr->cleanupProc)(segPtr, linePtr); - if (segPtr != *prevPtrPtr) { - anyChanges = 1; - } - } - } - if (!anyChanges) { - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeDeleteChars -- - * - * Delete a range of characters from a B-tree. The caller - * must make sure that the final newline of the B-tree is - * never deleted. - * - * Results: - * None. - * - * Side effects: - * Information is deleted from the B-tree. This can cause the - * internal structure of the B-tree to change. Note: because - * of changes to the B-tree structure, the indices pointed - * to by index1Ptr and index2Ptr should not be used after this - * procedure returns. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeDeleteChars(index1Ptr, index2Ptr) - register TkTextIndex *index1Ptr; /* Indicates first character that is - * to be deleted. */ - register TkTextIndex *index2Ptr; /* Indicates character just after the - * last one that is to be deleted. */ -{ - TkTextSegment *prevPtr; /* The segment just before the start - * of the deletion range. */ - TkTextSegment *lastPtr; /* The segment just after the end - * of the deletion range. */ - TkTextSegment *segPtr, *nextPtr; - TkTextLine *curLinePtr; - Node *curNodePtr, *nodePtr; - - /* - * Tricky point: split at index2Ptr first; otherwise the split - * at index2Ptr may invalidate segPtr and/or prevPtr. - */ - - lastPtr = SplitSeg(index2Ptr); - if (lastPtr != NULL) { - lastPtr = lastPtr->nextPtr; - } else { - lastPtr = index2Ptr->linePtr->segPtr; - } - prevPtr = SplitSeg(index1Ptr); - if (prevPtr != NULL) { - segPtr = prevPtr->nextPtr; - prevPtr->nextPtr = lastPtr; - } else { - segPtr = index1Ptr->linePtr->segPtr; - index1Ptr->linePtr->segPtr = lastPtr; - } - - /* - * Delete all of the segments between prevPtr and lastPtr. - */ - - curLinePtr = index1Ptr->linePtr; - curNodePtr = curLinePtr->parentPtr; - while (segPtr != lastPtr) { - if (segPtr == NULL) { - TkTextLine *nextLinePtr; - - /* - * We just ran off the end of a line. First find the - * next line, then go back to the old line and delete it - * (unless it's the starting line for the range). - */ - - nextLinePtr = TkBTreeNextLine(curLinePtr); - if (curLinePtr != index1Ptr->linePtr) { - if (curNodePtr == index1Ptr->linePtr->parentPtr) { - index1Ptr->linePtr->nextPtr = curLinePtr->nextPtr; - } else { - curNodePtr->children.linePtr = curLinePtr->nextPtr; - } - for (nodePtr = curNodePtr; nodePtr != NULL; - nodePtr = nodePtr->parentPtr) { - nodePtr->numLines--; - } - curNodePtr->numChildren--; - ckfree((char *) curLinePtr); - } - curLinePtr = nextLinePtr; - segPtr = curLinePtr->segPtr; - - /* - * If the node is empty then delete it and its parents, - * recursively upwards until a non-empty node is found. - */ - - while (curNodePtr->numChildren == 0) { - Node *parentPtr; - - parentPtr = curNodePtr->parentPtr; - if (parentPtr->children.nodePtr == curNodePtr) { - parentPtr->children.nodePtr = curNodePtr->nextPtr; - } else { - Node *prevNodePtr = parentPtr->children.nodePtr; - while (prevNodePtr->nextPtr != curNodePtr) { - prevNodePtr = prevNodePtr->nextPtr; - } - prevNodePtr->nextPtr = curNodePtr->nextPtr; - } - parentPtr->numChildren--; - ckfree((char *) curNodePtr); - curNodePtr = parentPtr; - } - curNodePtr = curLinePtr->parentPtr; - continue; - } - - nextPtr = segPtr->nextPtr; - if ((*segPtr->typePtr->deleteProc)(segPtr, curLinePtr, 0) != 0) { - /* - * This segment refuses to die. Move it to prevPtr and - * advance prevPtr if the segment has left gravity. - */ - - if (prevPtr == NULL) { - segPtr->nextPtr = index1Ptr->linePtr->segPtr; - index1Ptr->linePtr->segPtr = segPtr; - } else { - segPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = segPtr; - } - if (segPtr->typePtr->leftGravity) { - prevPtr = segPtr; - } - } - segPtr = nextPtr; - } - - /* - * If the beginning and end of the deletion range are in different - * lines, join the two lines together and discard the ending line. - */ - - if (index1Ptr->linePtr != index2Ptr->linePtr) { - TkTextLine *prevLinePtr; - - for (segPtr = lastPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr->lineChangeProc != NULL) { - (*segPtr->typePtr->lineChangeProc)(segPtr, index2Ptr->linePtr); - } - } - curNodePtr = index2Ptr->linePtr->parentPtr; - for (nodePtr = curNodePtr; nodePtr != NULL; - nodePtr = nodePtr->parentPtr) { - nodePtr->numLines--; - } - curNodePtr->numChildren--; - prevLinePtr = curNodePtr->children.linePtr; - if (prevLinePtr == index2Ptr->linePtr) { - curNodePtr->children.linePtr = index2Ptr->linePtr->nextPtr; - } else { - while (prevLinePtr->nextPtr != index2Ptr->linePtr) { - prevLinePtr = prevLinePtr->nextPtr; - } - prevLinePtr->nextPtr = index2Ptr->linePtr->nextPtr; - } - ckfree((char *) index2Ptr->linePtr); - Rebalance((BTree *) index2Ptr->tree, curNodePtr); - } - - /* - * Cleanup the segments in the new line. - */ - - CleanupLine(index1Ptr->linePtr); - - /* - * Lastly, rebalance the first node of the range. - */ - - Rebalance((BTree *) index1Ptr->tree, index1Ptr->linePtr->parentPtr); - if (tkBTreeDebug) { - TkBTreeCheck(index1Ptr->tree); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeFindLine -- - * - * Find a particular line in a B-tree based on its line number. - * - * Results: - * The return value is a pointer to the line structure for the - * line whose index is "line", or NULL if no such line exists. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkTextLine * -TkBTreeFindLine(tree, line) - TkTextBTree tree; /* B-tree in which to find line. */ - int line; /* Index of desired line. */ -{ - BTree *treePtr = (BTree *) tree; - register Node *nodePtr; - register TkTextLine *linePtr; - int linesLeft; - - nodePtr = treePtr->rootPtr; - linesLeft = line; - if ((line < 0) || (line >= nodePtr->numLines)) { - return NULL; - } - - /* - * Work down through levels of the tree until a node is found at - * level 0. - */ - - while (nodePtr->level != 0) { - for (nodePtr = nodePtr->children.nodePtr; - nodePtr->numLines <= linesLeft; - nodePtr = nodePtr->nextPtr) { - if (nodePtr == NULL) { - panic("TkBTreeFindLine ran out of nodes"); - } - linesLeft -= nodePtr->numLines; - } - } - - /* - * Work through the lines attached to the level-0 node. - */ - - for (linePtr = nodePtr->children.linePtr; linesLeft > 0; - linePtr = linePtr->nextPtr) { - if (linePtr == NULL) { - panic("TkBTreeFindLine ran out of lines"); - } - linesLeft -= 1; - } - return linePtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeNextLine -- - * - * Given an existing line in a B-tree, this procedure locates the - * next line in the B-tree. This procedure is used for scanning - * through the B-tree. - * - * Results: - * The return value is a pointer to the line that immediately - * follows linePtr, or NULL if there is no such line. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkTextLine * -TkBTreeNextLine(linePtr) - register TkTextLine *linePtr; /* Pointer to existing line in - * B-tree. */ -{ - register Node *nodePtr; - - if (linePtr->nextPtr != NULL) { - return linePtr->nextPtr; - } - - /* - * This was the last line associated with the particular parent node. - * Search up the tree for the next node, then search down from that - * node to find the first line. - */ - - for (nodePtr = linePtr->parentPtr; ; nodePtr = nodePtr->parentPtr) { - if (nodePtr->nextPtr != NULL) { - nodePtr = nodePtr->nextPtr; - break; - } - if (nodePtr->parentPtr == NULL) { - return (TkTextLine *) NULL; - } - } - while (nodePtr->level > 0) { - nodePtr = nodePtr->children.nodePtr; - } - return nodePtr->children.linePtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreePreviousLine -- - * - * Given an existing line in a B-tree, this procedure locates the - * previous line in the B-tree. This procedure is used for scanning - * through the B-tree in the reverse direction. - * - * Results: - * The return value is a pointer to the line that immediately - * preceeds linePtr, or NULL if there is no such line. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkTextLine * -TkBTreePreviousLine(linePtr) - register TkTextLine *linePtr; /* Pointer to existing line in - * B-tree. */ -{ - register Node *nodePtr; - register Node *node2Ptr; - register TkTextLine *prevPtr; - - /* - * Find the line under this node just before the starting line. - */ - prevPtr = linePtr->parentPtr->children.linePtr; /* First line at leaf */ - while (prevPtr != linePtr) { - if (prevPtr->nextPtr == linePtr) { - return prevPtr; - } - prevPtr = prevPtr->nextPtr; - if (prevPtr == (TkTextLine *) NULL) { - panic("TkBTreePreviousLine ran out of lines"); - } - } - - /* - * This was the first line associated with the particular parent node. - * Search up the tree for the previous node, then search down from that - * node to find its last line. - */ - for (nodePtr = linePtr->parentPtr; ; nodePtr = nodePtr->parentPtr) { - if (nodePtr == (Node *) NULL || nodePtr->parentPtr == (Node *) NULL) { - return (TkTextLine *) NULL; - } - if (nodePtr != nodePtr->parentPtr->children.nodePtr) { - break; - } - } - for (node2Ptr = nodePtr->parentPtr->children.nodePtr; ; - node2Ptr = node2Ptr->children.nodePtr) { - while (node2Ptr->nextPtr != nodePtr) { - node2Ptr = node2Ptr->nextPtr; - } - if (node2Ptr->level == 0) { - break; - } - nodePtr = (Node *)NULL; - } - for (prevPtr = node2Ptr->children.linePtr ; ; prevPtr = prevPtr->nextPtr) { - if (prevPtr->nextPtr == (TkTextLine *) NULL) { - return prevPtr; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeLineIndex -- - * - * Given a pointer to a line in a B-tree, return the numerical - * index of that line. - * - * Results: - * The result is the index of linePtr within the tree, where 0 - * corresponds to the first line in the tree. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeLineIndex(linePtr) - TkTextLine *linePtr; /* Pointer to existing line in - * B-tree. */ -{ - register TkTextLine *linePtr2; - register Node *nodePtr, *parentPtr, *nodePtr2; - int index; - - /* - * First count how many lines precede this one in its level-0 - * node. - */ - - nodePtr = linePtr->parentPtr; - index = 0; - for (linePtr2 = nodePtr->children.linePtr; linePtr2 != linePtr; - linePtr2 = linePtr2->nextPtr) { - if (linePtr2 == NULL) { - panic("TkBTreeLineIndex couldn't find line"); - } - index += 1; - } - - /* - * Now work up through the levels of the tree one at a time, - * counting how many lines are in nodes preceding the current - * node. - */ - - for (parentPtr = nodePtr->parentPtr ; parentPtr != NULL; - nodePtr = parentPtr, parentPtr = parentPtr->parentPtr) { - for (nodePtr2 = parentPtr->children.nodePtr; nodePtr2 != nodePtr; - nodePtr2 = nodePtr2->nextPtr) { - if (nodePtr2 == NULL) { - panic("TkBTreeLineIndex couldn't find node"); - } - index += nodePtr2->numLines; - } - } - return index; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeLinkSegment -- - * - * This procedure adds a new segment to a B-tree at a given - * location. - * - * Results: - * None. - * - * Side effects: - * SegPtr will be linked into its tree. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkBTreeLinkSegment(segPtr, indexPtr) - TkTextSegment *segPtr; /* Pointer to new segment to be added to - * B-tree. Should be completely initialized - * by caller except for nextPtr field. */ - TkTextIndex *indexPtr; /* Where to add segment: it gets linked - * in just before the segment indicated - * here. */ -{ - register TkTextSegment *prevPtr; - - prevPtr = SplitSeg(indexPtr); - if (prevPtr == NULL) { - segPtr->nextPtr = indexPtr->linePtr->segPtr; - indexPtr->linePtr->segPtr = segPtr; - } else { - segPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = segPtr; - } - CleanupLine(indexPtr->linePtr); - if (tkBTreeDebug) { - TkBTreeCheck(indexPtr->tree); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeUnlinkSegment -- - * - * This procedure unlinks a segment from its line in a B-tree. - * - * Results: - * None. - * - * Side effects: - * SegPtr will be unlinked from linePtr. The segment itself - * isn't modified by this procedure. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkBTreeUnlinkSegment(tree, segPtr, linePtr) - TkTextBTree tree; /* Tree containing segment. */ - TkTextSegment *segPtr; /* Segment to be unlinked. */ - TkTextLine *linePtr; /* Line that currently contains - * segment. */ -{ - register TkTextSegment *prevPtr; - - if (linePtr->segPtr == segPtr) { - linePtr->segPtr = segPtr->nextPtr; - } else { - for (prevPtr = linePtr->segPtr; prevPtr->nextPtr != segPtr; - prevPtr = prevPtr->nextPtr) { - /* Empty loop body. */ - } - prevPtr->nextPtr = segPtr->nextPtr; - } - CleanupLine(linePtr); -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeTag -- - * - * Turn a given tag on or off for a given range of characters in - * a B-tree of text. - * - * Results: - * None. - * - * Side effects: - * The given tag is added to the given range of characters - * in the tree or removed from all those characters, depending - * on the "add" argument. The structure of the btree is modified - * enough that index1Ptr and index2Ptr are no longer valid after - * this procedure returns, and the indexes may be modified by - * this procedure. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeTag(index1Ptr, index2Ptr, tagPtr, add) - register TkTextIndex *index1Ptr; /* Indicates first character in - * range. */ - register TkTextIndex *index2Ptr; /* Indicates character just after the - * last one in range. */ - TkTextTag *tagPtr; /* Tag to add or remove. */ - int add; /* One means add tag to the given - * range of characters; zero means - * remove the tag from the range. */ -{ - TkTextSegment *segPtr, *prevPtr; - TkTextSearch search; - TkTextLine *cleanupLinePtr; - int oldState; - int changed; - - /* - * See whether the tag is present at the start of the range. If - * the state doesn't already match what we want then add a toggle - * there. - */ - - oldState = TkBTreeCharTagged(index1Ptr, tagPtr); - if ((add != 0) ^ oldState) { - segPtr = (TkTextSegment *) ckalloc(TSEG_SIZE); - segPtr->typePtr = (add) ? &tkTextToggleOnType : &tkTextToggleOffType; - prevPtr = SplitSeg(index1Ptr); - if (prevPtr == NULL) { - segPtr->nextPtr = index1Ptr->linePtr->segPtr; - index1Ptr->linePtr->segPtr = segPtr; - } else { - segPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = segPtr; - } - segPtr->size = 0; - segPtr->body.toggle.tagPtr = tagPtr; - segPtr->body.toggle.inNodeCounts = 0; - } - - /* - * Scan the range of characters and delete any internal tag - * transitions. Keep track of what the old state was at the end - * of the range, and add a toggle there if it's needed. - */ - - TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search); - cleanupLinePtr = index1Ptr->linePtr; - while (TkBTreeNextTag(&search)) { - oldState ^= 1; - segPtr = search.segPtr; - prevPtr = search.curIndex.linePtr->segPtr; - if (prevPtr == segPtr) { - search.curIndex.linePtr->segPtr = segPtr->nextPtr; - } else { - while (prevPtr->nextPtr != segPtr) { - prevPtr = prevPtr->nextPtr; - } - prevPtr->nextPtr = segPtr->nextPtr; - } - if (segPtr->body.toggle.inNodeCounts) { - ChangeNodeToggleCount(search.curIndex.linePtr->parentPtr, - segPtr->body.toggle.tagPtr, -1); - segPtr->body.toggle.inNodeCounts = 0; - changed = 1; - } else { - changed = 0; - } - ckfree((char *) segPtr); - - /* - * The code below is a bit tricky. After deleting a toggle - * we eventually have to call CleanupLine, in order to allow - * character segments to be merged together. To do this, we - * remember in cleanupLinePtr a line that needs to be - * cleaned up, but we don't clean it up until we've moved - * on to a different line. That way the cleanup process - * won't goof up segPtr. - */ - - if (cleanupLinePtr != search.curIndex.linePtr) { - CleanupLine(cleanupLinePtr); - cleanupLinePtr = search.curIndex.linePtr; - } - /* - * Quick hack. ChangeNodeToggleCount may move the tag's root - * location around and leave the search in the void. This resets - * the search. - */ - if (changed) { - TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search); - } - } - if ((add != 0) ^ oldState) { - segPtr = (TkTextSegment *) ckalloc(TSEG_SIZE); - segPtr->typePtr = (add) ? &tkTextToggleOffType : &tkTextToggleOnType; - prevPtr = SplitSeg(index2Ptr); - if (prevPtr == NULL) { - segPtr->nextPtr = index2Ptr->linePtr->segPtr; - index2Ptr->linePtr->segPtr = segPtr; - } else { - segPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = segPtr; - } - segPtr->size = 0; - segPtr->body.toggle.tagPtr = tagPtr; - segPtr->body.toggle.inNodeCounts = 0; - } - - /* - * Cleanup cleanupLinePtr and the last line of the range, if - * these are different. - */ - - CleanupLine(cleanupLinePtr); - if (cleanupLinePtr != index2Ptr->linePtr) { - CleanupLine(index2Ptr->linePtr); - } - - if (tkBTreeDebug) { - TkBTreeCheck(index1Ptr->tree); - } -} - -/* - *---------------------------------------------------------------------- - * - * ChangeNodeToggleCount -- - * - * This procedure increments or decrements the toggle count for - * a particular tag in a particular node and all its ancestors - * up to the per-tag root node. - * - * Results: - * None. - * - * Side effects: - * The toggle count for tag is adjusted up or down by "delta" in - * nodePtr. This routine maintains the tagRootPtr that identifies - * the root node for the tag, moving it up or down the tree as needed. - * - *---------------------------------------------------------------------- - */ - -static void -ChangeNodeToggleCount(nodePtr, tagPtr, delta) - register Node *nodePtr; /* Node whose toggle count for a tag - * must be changed. */ - TkTextTag *tagPtr; /* Information about tag. */ - int delta; /* Amount to add to current toggle - * count for tag (may be negative). */ -{ - register Summary *summaryPtr, *prevPtr; - register Node *node2Ptr; - int rootLevel; /* Level of original tag root */ - - tagPtr->toggleCount += delta; - if (tagPtr->tagRootPtr == (Node *) NULL) { - tagPtr->tagRootPtr = nodePtr; - return; - } - - /* - * Note the level of the existing root for the tag so we can detect - * if it needs to be moved because of the toggle count change. - */ - - rootLevel = tagPtr->tagRootPtr->level; - - /* - * Iterate over the node and its ancestors up to the tag root, adjusting - * summary counts at each node and moving the tag's root upwards if - * necessary. - */ - - for ( ; nodePtr != tagPtr->tagRootPtr; nodePtr = nodePtr->parentPtr) { - /* - * See if there's already an entry for this tag for this node. If so, - * perhaps all we have to do is adjust its count. - */ - - for (prevPtr = NULL, summaryPtr = nodePtr->summaryPtr; - summaryPtr != NULL; - prevPtr = summaryPtr, summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - break; - } - } - if (summaryPtr != NULL) { - summaryPtr->toggleCount += delta; - if (summaryPtr->toggleCount > 0 && - summaryPtr->toggleCount < tagPtr->toggleCount) { - continue; - } - if (summaryPtr->toggleCount != 0) { - /* - * Should never find a node with max toggle count at this - * point (there shouldn't have been a summary entry in the - * first place). - */ - - panic("ChangeNodeToggleCount: bad toggle count (%d) max (%d)", - summaryPtr->toggleCount, tagPtr->toggleCount); - } - - /* - * Zero toggle count; must remove this tag from the list. - */ - - if (prevPtr == NULL) { - nodePtr->summaryPtr = summaryPtr->nextPtr; - } else { - prevPtr->nextPtr = summaryPtr->nextPtr; - } - ckfree((char *) summaryPtr); - } else { - /* - * This tag isn't currently in the summary information list. - */ - - if (rootLevel == nodePtr->level) { - - /* - * The old tag root is at the same level in the tree as this - * node, but it isn't at this node. Move the tag root up - * a level, in the hopes that it will now cover this node - * as well as the old root (if not, we'll move it up again - * the next time through the loop). To push it up one level - * we copy the original toggle count into the summary - * information at the old root and change the root to its - * parent node. - */ - - Node *rootNodePtr = tagPtr->tagRootPtr; - summaryPtr = (Summary *) ckalloc(sizeof(Summary)); - summaryPtr->tagPtr = tagPtr; - summaryPtr->toggleCount = tagPtr->toggleCount - delta; - summaryPtr->nextPtr = rootNodePtr->summaryPtr; - rootNodePtr->summaryPtr = summaryPtr; - rootNodePtr = rootNodePtr->parentPtr; - rootLevel = rootNodePtr->level; - tagPtr->tagRootPtr = rootNodePtr; - } - summaryPtr = (Summary *) ckalloc(sizeof(Summary)); - summaryPtr->tagPtr = tagPtr; - summaryPtr->toggleCount = delta; - summaryPtr->nextPtr = nodePtr->summaryPtr; - nodePtr->summaryPtr = summaryPtr; - } - } - - /* - * If we've decremented the toggle count, then it may be necessary - * to push the tag root down one or more levels. - */ - - if (delta >= 0) { - return; - } - if (tagPtr->toggleCount == 0) { - tagPtr->tagRootPtr = (Node *) NULL; - return; - } - nodePtr = tagPtr->tagRootPtr; - while (nodePtr->level > 0) { - /* - * See if a single child node accounts for all of the tag's - * toggles. If so, push the root down one level. - */ - - for (node2Ptr = nodePtr->children.nodePtr; - node2Ptr != (Node *)NULL ; - node2Ptr = node2Ptr->nextPtr) { - for (prevPtr = NULL, summaryPtr = node2Ptr->summaryPtr; - summaryPtr != NULL; - prevPtr = summaryPtr, summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - break; - } - } - if (summaryPtr == NULL) { - continue; - } - if (summaryPtr->toggleCount != tagPtr->toggleCount) { - /* - * No node has all toggles, so the root is still valid. - */ - - return; - } - - /* - * This node has all the toggles, so push down the root. - */ - - if (prevPtr == NULL) { - node2Ptr->summaryPtr = summaryPtr->nextPtr; - } else { - prevPtr->nextPtr = summaryPtr->nextPtr; - } - ckfree((char *) summaryPtr); - tagPtr->tagRootPtr = node2Ptr; - break; - } - nodePtr = tagPtr->tagRootPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * FindTagStart -- - * - * Find the start of the first range of a tag. - * - * Results: - * The return value is a pointer to the first tag toggle segment - * for the tag. This can be either a tagon or tagoff segments because - * of the way TkBTreeAdd removes a tag. - * Sets *indexPtr to be the index of the tag toggle. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static TkTextSegment * -FindTagStart(tree, tagPtr, indexPtr) - TkTextBTree tree; /* Tree to search within */ - TkTextTag *tagPtr; /* Tag to search for. */ - TkTextIndex *indexPtr; /* Return - index information */ -{ - register Node *nodePtr; - register TkTextLine *linePtr; - register TkTextSegment *segPtr; - register Summary *summaryPtr; - int offset; - - nodePtr = tagPtr->tagRootPtr; - if (nodePtr == (Node *) NULL) { - return NULL; - } - - /* - * Search from the root of the subtree that contains the tag down - * to the level 0 node. - */ - - while (nodePtr->level > 0) { - for (nodePtr = nodePtr->children.nodePtr ; nodePtr != (Node *) NULL; - nodePtr = nodePtr->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr ; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - goto gotNodeWithTag; - } - } - } - gotNodeWithTag: - continue; - } - - /* - * Work through the lines attached to the level-0 node. - */ - - for (linePtr = nodePtr->children.linePtr; linePtr != (TkTextLine *) NULL; - linePtr = linePtr->nextPtr) { - for (offset = 0, segPtr = linePtr->segPtr ; segPtr != NULL; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (segPtr->body.toggle.tagPtr == tagPtr)) { - /* - * It is possible that this is a tagoff tag, but that - * gets cleaned up later. - */ - indexPtr->tree = tree; - indexPtr->linePtr = linePtr; - indexPtr->charIndex = offset; - return segPtr; - } - } - } - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * FindTagEnd -- - * - * Find the end of the last range of a tag. - * - * Results: - * The return value is a pointer to the last tag toggle segment - * for the tag. This can be either a tagon or tagoff segments because - * of the way TkBTreeAdd removes a tag. - * Sets *indexPtr to be the index of the tag toggle. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static TkTextSegment * -FindTagEnd(tree, tagPtr, indexPtr) - TkTextBTree tree; /* Tree to search within */ - TkTextTag *tagPtr; /* Tag to search for. */ - TkTextIndex *indexPtr; /* Return - index information */ -{ - register Node *nodePtr, *lastNodePtr; - register TkTextLine *linePtr ,*lastLinePtr; - register TkTextSegment *segPtr, *lastSegPtr, *last2SegPtr; - register Summary *summaryPtr; - int lastoffset, lastoffset2, offset; - - nodePtr = tagPtr->tagRootPtr; - if (nodePtr == (Node *) NULL) { - return NULL; - } - - /* - * Search from the root of the subtree that contains the tag down - * to the level 0 node. - */ - - while (nodePtr->level > 0) { - for (lastNodePtr = NULL, nodePtr = nodePtr->children.nodePtr ; - nodePtr != (Node *) NULL; nodePtr = nodePtr->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr ; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - lastNodePtr = nodePtr; - break; - } - } - } - nodePtr = lastNodePtr; - } - - /* - * Work through the lines attached to the level-0 node. - */ - last2SegPtr = NULL; - lastoffset2 = 0; - lastoffset = 0; - for (lastLinePtr = NULL, linePtr = nodePtr->children.linePtr; - linePtr != (TkTextLine *) NULL; linePtr = linePtr->nextPtr) { - for (offset = 0, lastSegPtr = NULL, segPtr = linePtr->segPtr ; - segPtr != NULL; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (segPtr->body.toggle.tagPtr == tagPtr)) { - lastSegPtr = segPtr; - lastoffset = offset; - } - } - if (lastSegPtr != NULL) { - lastLinePtr = linePtr; - last2SegPtr = lastSegPtr; - lastoffset2 = lastoffset; - } - } - indexPtr->tree = tree; - indexPtr->linePtr = lastLinePtr; - indexPtr->charIndex = lastoffset2; - return last2SegPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeStartSearch -- - * - * This procedure sets up a search for tag transitions involving - * a given tag (or all tags) in a given range of the text. - * - * Results: - * None. - * - * Side effects: - * The information at *searchPtr is set up so that subsequent calls - * to TkBTreeNextTag or TkBTreePrevTag will return information about the - * locations of tag transitions. Note that TkBTreeNextTag or - * TkBTreePrevTag must be called to get the first transition. - * Note: unlike TkBTreeNextTag and TkBTreePrevTag, this routine does not - * guarantee that searchPtr->curIndex is equal to *index1Ptr. It may be - * greater than that if *index1Ptr is less than the first tag transition. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, searchPtr) - TkTextIndex *index1Ptr; /* Search starts here. Tag toggles - * at this position will not be - * returned. */ - TkTextIndex *index2Ptr; /* Search stops here. Tag toggles - * at this position *will* be - * returned. */ - TkTextTag *tagPtr; /* Tag to search for. NULL means - * search for any tag. */ - register TkTextSearch *searchPtr; /* Where to store information about - * search's progress. */ -{ - int offset; - TkTextIndex index0; /* First index of the tag */ - TkTextSegment *seg0Ptr; /* First segment of the tag */ - - /* - * Find the segment that contains the first toggle for the tag. This - * may become the starting point in the search. - */ - - seg0Ptr = FindTagStart(index1Ptr->tree, tagPtr, &index0); - if (seg0Ptr == (TkTextSegment *) NULL) { - /* - * Even though there are no toggles, the display code still - * uses the search curIndex, so initialize that anyway. - */ - - searchPtr->linesLeft = 0; - searchPtr->curIndex = *index1Ptr; - searchPtr->segPtr = NULL; - searchPtr->nextPtr = NULL; - return; - } - if (TkTextIndexCmp(index1Ptr, &index0) < 0) { - /* - * Adjust start of search up to the first range of the tag - */ - - searchPtr->curIndex = index0; - searchPtr->segPtr = NULL; - searchPtr->nextPtr = seg0Ptr; /* Will be returned by NextTag */ - index1Ptr = &index0; - } else { - searchPtr->curIndex = *index1Ptr; - searchPtr->segPtr = NULL; - searchPtr->nextPtr = TkTextIndexToSeg(index1Ptr, &offset); - searchPtr->curIndex.charIndex -= offset; - } - searchPtr->lastPtr = TkTextIndexToSeg(index2Ptr, (int *) NULL); - searchPtr->tagPtr = tagPtr; - searchPtr->linesLeft = TkBTreeLineIndex(index2Ptr->linePtr) + 1 - - TkBTreeLineIndex(index1Ptr->linePtr); - searchPtr->allTags = (tagPtr == NULL); - if (searchPtr->linesLeft == 1) { - /* - * Starting and stopping segments are in the same line; mark the - * search as over immediately if the second segment is before the - * first. A search does not return a toggle at the very start of - * the range, unless the range is artificially moved up to index0. - */ - if (((index1Ptr == &index0) && - (index1Ptr->charIndex > index2Ptr->charIndex)) || - ((index1Ptr != &index0) && - (index1Ptr->charIndex >= index2Ptr->charIndex))) { - searchPtr->linesLeft = 0; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeStartSearchBack -- - * - * This procedure sets up a search backwards for tag transitions involving - * a given tag (or all tags) in a given range of the text. In the - * normal case the first index (*index1Ptr) is beyond the second - * index (*index2Ptr). - * - * - * Results: - * None. - * - * Side effects: - * The information at *searchPtr is set up so that subsequent calls - * to TkBTreePrevTag will return information about the - * locations of tag transitions. Note that TkBTreePrevTag must be called - * to get the first transition. - * Note: unlike TkBTreeNextTag and TkBTreePrevTag, this routine does not - * guarantee that searchPtr->curIndex is equal to *index1Ptr. It may be - * less than that if *index1Ptr is greater than the last tag transition. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) - TkTextIndex *index1Ptr; /* Search starts here. Tag toggles - * at this position will not be - * returned. */ - TkTextIndex *index2Ptr; /* Search stops here. Tag toggles - * at this position *will* be - * returned. */ - TkTextTag *tagPtr; /* Tag to search for. NULL means - * search for any tag. */ - register TkTextSearch *searchPtr; /* Where to store information about - * search's progress. */ -{ - int offset; - TkTextIndex index0; /* Last index of the tag */ - TkTextIndex backOne; /* One character before starting index */ - TkTextSegment *seg0Ptr; /* Last segment of the tag */ - - /* - * Find the segment that contains the last toggle for the tag. This - * may become the starting point in the search. - */ - - seg0Ptr = FindTagEnd(index1Ptr->tree, tagPtr, &index0); - if (seg0Ptr == (TkTextSegment *) NULL) { - /* - * Even though there are no toggles, the display code still - * uses the search curIndex, so initialize that anyway. - */ - - searchPtr->linesLeft = 0; - searchPtr->curIndex = *index1Ptr; - searchPtr->segPtr = NULL; - searchPtr->nextPtr = NULL; - return; - } - - /* - * Adjust the start of the search so it doesn't find any tag toggles - * that are right at the index specified by the user. - */ - - if (TkTextIndexCmp(index1Ptr, &index0) > 0) { - searchPtr->curIndex = index0; - index1Ptr = &index0; - } else { - TkTextIndexBackChars(index1Ptr, 1, &searchPtr->curIndex); - } - searchPtr->segPtr = NULL; - searchPtr->nextPtr = TkTextIndexToSeg(&searchPtr->curIndex, &offset); - searchPtr->curIndex.charIndex -= offset; - - /* - * Adjust the end of the search so it does find toggles that are right - * at the second index specified by the user. - */ - - if ((TkBTreeLineIndex(index2Ptr->linePtr) == 0) && - (index2Ptr->charIndex == 0)) { - backOne = *index2Ptr; - searchPtr->lastPtr = NULL; /* Signals special case for 1.0 */ - } else { - TkTextIndexBackChars(index2Ptr, 1, &backOne); - searchPtr->lastPtr = TkTextIndexToSeg(&backOne, (int *) NULL); - } - searchPtr->tagPtr = tagPtr; - searchPtr->linesLeft = TkBTreeLineIndex(index1Ptr->linePtr) + 1 - - TkBTreeLineIndex(backOne.linePtr); - searchPtr->allTags = (tagPtr == NULL); - if (searchPtr->linesLeft == 1) { - /* - * Starting and stopping segments are in the same line; mark the - * search as over immediately if the second segment is after the - * first. - */ - - if (index1Ptr->charIndex <= backOne.charIndex) { - searchPtr->linesLeft = 0; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeNextTag -- - * - * Once a tag search has begun, successive calls to this procedure - * return successive tag toggles. Note: it is NOT SAFE to call this - * procedure if characters have been inserted into or deleted from - * the B-tree since the call to TkBTreeStartSearch. - * - * Results: - * The return value is 1 if another toggle was found that met the - * criteria specified in the call to TkBTreeStartSearch; in this - * case searchPtr->curIndex gives the toggle's position and - * searchPtr->curTagPtr points to its segment. 0 is returned if - * no more matching tag transitions were found; in this case - * searchPtr->curIndex is the same as searchPtr->stopIndex. - * - * Side effects: - * Information in *searchPtr is modified to update the state of the - * search and indicate where the next tag toggle is located. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeNextTag(searchPtr) - register TkTextSearch *searchPtr; /* Information about search in - * progress; must have been set up by - * call to TkBTreeStartSearch. */ -{ - register TkTextSegment *segPtr; - register Node *nodePtr; - register Summary *summaryPtr; - - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - - /* - * The outermost loop iterates over lines that may potentially contain - * a relevant tag transition, starting from the current segment in - * the current line. - */ - - segPtr = searchPtr->nextPtr; - while (1) { - /* - * Check for more tags on the current line. - */ - - for ( ; segPtr != NULL; segPtr = segPtr->nextPtr) { - if (segPtr == searchPtr->lastPtr) { - goto searchOver; - } - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (searchPtr->allTags - || (segPtr->body.toggle.tagPtr == searchPtr->tagPtr))) { - searchPtr->segPtr = segPtr; - searchPtr->nextPtr = segPtr->nextPtr; - searchPtr->tagPtr = segPtr->body.toggle.tagPtr; - return 1; - } - searchPtr->curIndex.charIndex += segPtr->size; - } - - /* - * See if there are more lines associated with the current parent - * node. If so, go back to the top of the loop to search the next - * one. - */ - - nodePtr = searchPtr->curIndex.linePtr->parentPtr; - searchPtr->curIndex.linePtr = searchPtr->curIndex.linePtr->nextPtr; - searchPtr->linesLeft--; - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - if (searchPtr->curIndex.linePtr != NULL) { - segPtr = searchPtr->curIndex.linePtr->segPtr; - searchPtr->curIndex.charIndex = 0; - continue; - } - if (nodePtr == searchPtr->tagPtr->tagRootPtr) { - goto searchOver; - } - - /* - * Search across and up through the B-tree's node hierarchy looking - * for the next node that has a relevant tag transition somewhere in - * its subtree. Be sure to update linesLeft as we skip over large - * chunks of lines. - */ - - while (1) { - while (nodePtr->nextPtr == NULL) { - if (nodePtr->parentPtr == NULL || - nodePtr->parentPtr == searchPtr->tagPtr->tagRootPtr) { - goto searchOver; - } - nodePtr = nodePtr->parentPtr; - } - nodePtr = nodePtr->nextPtr; - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if ((searchPtr->allTags) || - (summaryPtr->tagPtr == searchPtr->tagPtr)) { - goto gotNodeWithTag; - } - } - searchPtr->linesLeft -= nodePtr->numLines; - } - - /* - * At this point we've found a subtree that has a relevant tag - * transition. Now search down (and across) through that subtree - * to find the first level-0 node that has a relevant tag transition. - */ - - gotNodeWithTag: - while (nodePtr->level > 0) { - for (nodePtr = nodePtr->children.nodePtr; ; - nodePtr = nodePtr->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if ((searchPtr->allTags) - || (summaryPtr->tagPtr == searchPtr->tagPtr)) { - goto nextChild; - } - } - searchPtr->linesLeft -= nodePtr->numLines; - if (nodePtr->nextPtr == NULL) { - panic("TkBTreeNextTag found incorrect tag summary info."); - } - } - nextChild: - continue; - } - - /* - * Now we're down to a level-0 node that contains a line that contains - * a relevant tag transition. Set up line information and go back to - * the beginning of the loop to search through lines. - */ - - searchPtr->curIndex.linePtr = nodePtr->children.linePtr; - searchPtr->curIndex.charIndex = 0; - segPtr = searchPtr->curIndex.linePtr->segPtr; - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - continue; - } - - searchOver: - searchPtr->linesLeft = 0; - searchPtr->segPtr = NULL; - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreePrevTag -- - * - * Once a tag search has begun, successive calls to this procedure - * return successive tag toggles in the reverse direction. - * Note: it is NOT SAFE to call this - * procedure if characters have been inserted into or deleted from - * the B-tree since the call to TkBTreeStartSearch. - * - * Results: - * The return value is 1 if another toggle was found that met the - * criteria specified in the call to TkBTreeStartSearch; in this - * case searchPtr->curIndex gives the toggle's position and - * searchPtr->curTagPtr points to its segment. 0 is returned if - * no more matching tag transitions were found; in this case - * searchPtr->curIndex is the same as searchPtr->stopIndex. - * - * Side effects: - * Information in *searchPtr is modified to update the state of the - * search and indicate where the next tag toggle is located. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreePrevTag(searchPtr) - register TkTextSearch *searchPtr; /* Information about search in - * progress; must have been set up by - * call to TkBTreeStartSearch. */ -{ - register TkTextSegment *segPtr, *prevPtr; - register TkTextLine *linePtr, *prevLinePtr; - register Node *nodePtr, *node2Ptr, *prevNodePtr; - register Summary *summaryPtr; - int charIndex; - int pastLast; /* Saw last marker during scan */ - int linesSkipped; - - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - - /* - * The outermost loop iterates over lines that may potentially contain - * a relevant tag transition, starting from the current segment in - * the current line. "nextPtr" is maintained as the last segment in - * a line that we can look at. - */ - - while (1) { - /* - * Check for the last toggle before the current segment on this line. - */ - charIndex = 0; - if (searchPtr->lastPtr == NULL) { - /* - * Search back to the very beginning, so pastLast is irrelevent. - */ - pastLast = 1; - } else { - pastLast = 0; - } - for (prevPtr = NULL, segPtr = searchPtr->curIndex.linePtr->segPtr ; - segPtr != NULL && segPtr != searchPtr->nextPtr; - segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (searchPtr->allTags - || (segPtr->body.toggle.tagPtr == searchPtr->tagPtr))) { - prevPtr = segPtr; - searchPtr->curIndex.charIndex = charIndex; - } - if (segPtr == searchPtr->lastPtr) { - prevPtr = NULL; /* Segments earlier than last don't count */ - pastLast = 1; - } - charIndex += segPtr->size; - } - if (prevPtr != NULL) { - if (searchPtr->linesLeft == 1 && !pastLast) { - /* - * We found a segment that is before the stopping index. - * Note that it is OK if prevPtr == lastPtr. - */ - goto searchOver; - } - searchPtr->segPtr = prevPtr; - searchPtr->nextPtr = prevPtr; - searchPtr->tagPtr = prevPtr->body.toggle.tagPtr; - return 1; - } - - searchPtr->linesLeft--; - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - - /* - * See if there are more lines associated with the current parent - * node. If so, go back to the top of the loop to search the previous - * one. - */ - - nodePtr = searchPtr->curIndex.linePtr->parentPtr; - for (prevLinePtr = NULL, linePtr = nodePtr->children.linePtr; - linePtr != NULL && linePtr != searchPtr->curIndex.linePtr; - prevLinePtr = linePtr, linePtr = linePtr->nextPtr) { - /* empty loop body */ ; - } - if (prevLinePtr != NULL) { - searchPtr->curIndex.linePtr = prevLinePtr; - searchPtr->nextPtr = NULL; - continue; - } - if (nodePtr == searchPtr->tagPtr->tagRootPtr) { - goto searchOver; - } - - /* - * Search across and up through the B-tree's node hierarchy looking - * for the previous node that has a relevant tag transition somewhere in - * its subtree. The search and line counting is trickier with/out - * back pointers. We'll scan all the nodes under a parent up to - * the current node, searching all of them for tag state. The last - * one we find, if any, is recorded in prevNodePtr, and any nodes - * past prevNodePtr that don't have tag state increment linesSkipped. - */ - - while (1) { - for (prevNodePtr = NULL, linesSkipped = 0, - node2Ptr = nodePtr->parentPtr->children.nodePtr ; - node2Ptr != nodePtr; node2Ptr = node2Ptr->nextPtr) { - for (summaryPtr = node2Ptr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if ((searchPtr->allTags) || - (summaryPtr->tagPtr == searchPtr->tagPtr)) { - prevNodePtr = node2Ptr; - linesSkipped = 0; - goto keepLooking; - } - } - linesSkipped += node2Ptr->numLines; - - keepLooking: - continue; - } - if (prevNodePtr != NULL) { - nodePtr = prevNodePtr; - searchPtr->linesLeft -= linesSkipped; - goto gotNodeWithTag; - } - nodePtr = nodePtr->parentPtr; - if (nodePtr->parentPtr == NULL || - nodePtr == searchPtr->tagPtr->tagRootPtr) { - goto searchOver; - } - } - - /* - * At this point we've found a subtree that has a relevant tag - * transition. Now search down (and across) through that subtree - * to find the last level-0 node that has a relevant tag transition. - */ - - gotNodeWithTag: - while (nodePtr->level > 0) { - for (linesSkipped = 0, prevNodePtr = NULL, - nodePtr = nodePtr->children.nodePtr; nodePtr != NULL ; - nodePtr = nodePtr->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if ((searchPtr->allTags) - || (summaryPtr->tagPtr == searchPtr->tagPtr)) { - prevNodePtr = nodePtr; - linesSkipped = 0; - goto keepLooking2; - } - } - linesSkipped += nodePtr->numLines; - - keepLooking2: - continue; - } - if (prevNodePtr == NULL) { - panic("TkBTreePrevTag found incorrect tag summary info."); - } - searchPtr->linesLeft -= linesSkipped; - nodePtr = prevNodePtr; - } - - /* - * Now we're down to a level-0 node that contains a line that contains - * a relevant tag transition. Set up line information and go back to - * the beginning of the loop to search through lines. We start with - * the last line below the node. - */ - - for (prevLinePtr = NULL, linePtr = nodePtr->children.linePtr; - linePtr != NULL ; - prevLinePtr = linePtr, linePtr = linePtr->nextPtr) { - /* empty loop body */ ; - } - searchPtr->curIndex.linePtr = prevLinePtr; - searchPtr->curIndex.charIndex = 0; - if (searchPtr->linesLeft <= 0) { - goto searchOver; - } - continue; - } - - searchOver: - searchPtr->linesLeft = 0; - searchPtr->segPtr = NULL; - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeCharTagged -- - * - * Determine whether a particular character has a particular tag. - * - * Results: - * The return value is 1 if the given tag is in effect at the - * character given by linePtr and ch, and 0 otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeCharTagged(indexPtr, tagPtr) - TkTextIndex *indexPtr; /* Indicates a character position at - * which to check for a tag. */ - TkTextTag *tagPtr; /* Tag of interest. */ -{ - register Node *nodePtr; - register TkTextLine *siblingLinePtr; - register TkTextSegment *segPtr; - TkTextSegment *toggleSegPtr; - int toggles, index; - - /* - * Check for toggles for the tag in indexPtr's line but before - * indexPtr. If there is one, its type indicates whether or - * not the character is tagged. - */ - - toggleSegPtr = NULL; - for (index = 0, segPtr = indexPtr->linePtr->segPtr; - (index + segPtr->size) <= indexPtr->charIndex; - index += segPtr->size, segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (segPtr->body.toggle.tagPtr == tagPtr)) { - toggleSegPtr = segPtr; - } - } - if (toggleSegPtr != NULL) { - return (toggleSegPtr->typePtr == &tkTextToggleOnType); - } - - /* - * No toggle in this line. Look for toggles for the tag in lines - * that are predecessors of indexPtr->linePtr but under the same - * level-0 node. - */ - - for (siblingLinePtr = indexPtr->linePtr->parentPtr->children.linePtr; - siblingLinePtr != indexPtr->linePtr; - siblingLinePtr = siblingLinePtr->nextPtr) { - for (segPtr = siblingLinePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) - && (segPtr->body.toggle.tagPtr == tagPtr)) { - toggleSegPtr = segPtr; - } - } - } - if (toggleSegPtr != NULL) { - return (toggleSegPtr->typePtr == &tkTextToggleOnType); - } - - /* - * No toggle in this node. Scan upwards through the ancestors of - * this node, counting the number of toggles of the given tag in - * siblings that precede that node. - */ - - toggles = 0; - for (nodePtr = indexPtr->linePtr->parentPtr; nodePtr->parentPtr != NULL; - nodePtr = nodePtr->parentPtr) { - register Node *siblingPtr; - register Summary *summaryPtr; - - for (siblingPtr = nodePtr->parentPtr->children.nodePtr; - siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) { - for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - toggles += summaryPtr->toggleCount; - } - } - } - if (nodePtr == tagPtr->tagRootPtr) { - break; - } - } - - /* - * An odd number of toggles means that the tag is present at the - * given point. - */ - - return toggles & 1; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeGetTags -- - * - * Return information about all of the tags that are associated - * with a particular character in a B-tree of text. - * - * Results: - * The return value is a malloc-ed array containing pointers to - * information for each of the tags that is associated with - * the character at the position given by linePtr and ch. The - * word at *numTagsPtr is filled in with the number of pointers - * in the array. It is up to the caller to free the array by - * passing it to free. If there are no tags at the given character - * then a NULL pointer is returned and *numTagsPtr will be set to 0. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -TkTextTag ** -TkBTreeGetTags(indexPtr, numTagsPtr) - TkTextIndex *indexPtr; /* Indicates a particular position in - * the B-tree. */ - int *numTagsPtr; /* Store number of tags found at this - * location. */ -{ - register Node *nodePtr; - register TkTextLine *siblingLinePtr; - register TkTextSegment *segPtr; - int src, dst, index; - TagInfo tagInfo; -#define NUM_TAG_INFOS 10 - - tagInfo.numTags = 0; - tagInfo.arraySize = NUM_TAG_INFOS; - tagInfo.tagPtrs = (TkTextTag **) ckalloc((unsigned) - NUM_TAG_INFOS*sizeof(TkTextTag *)); - tagInfo.counts = (int *) ckalloc((unsigned) - NUM_TAG_INFOS*sizeof(int)); - - /* - * Record tag toggles within the line of indexPtr but preceding - * indexPtr. - */ - - for (index = 0, segPtr = indexPtr->linePtr->segPtr; - (index + segPtr->size) <= indexPtr->charIndex; - index += segPtr->size, segPtr = segPtr->nextPtr) { - if ((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) { - IncCount(segPtr->body.toggle.tagPtr, 1, &tagInfo); - } - } - - /* - * Record toggles for tags in lines that are predecessors of - * indexPtr->linePtr but under the same level-0 node. - */ - - for (siblingLinePtr = indexPtr->linePtr->parentPtr->children.linePtr; - siblingLinePtr != indexPtr->linePtr; - siblingLinePtr = siblingLinePtr->nextPtr) { - for (segPtr = siblingLinePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if ((segPtr->typePtr == &tkTextToggleOnType) - || (segPtr->typePtr == &tkTextToggleOffType)) { - IncCount(segPtr->body.toggle.tagPtr, 1, &tagInfo); - } - } - } - - /* - * For each node in the ancestry of this line, record tag toggles - * for all siblings that precede that node. - */ - - for (nodePtr = indexPtr->linePtr->parentPtr; nodePtr->parentPtr != NULL; - nodePtr = nodePtr->parentPtr) { - register Node *siblingPtr; - register Summary *summaryPtr; - - for (siblingPtr = nodePtr->parentPtr->children.nodePtr; - siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) { - for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->toggleCount & 1) { - IncCount(summaryPtr->tagPtr, summaryPtr->toggleCount, - &tagInfo); - } - } - } - } - - /* - * Go through the tag information and squash out all of the tags - * that have even toggle counts (these tags exist before the point - * of interest, but not at the desired character itself). - */ - - for (src = 0, dst = 0; src < tagInfo.numTags; src++) { - if (tagInfo.counts[src] & 1) { - tagInfo.tagPtrs[dst] = tagInfo.tagPtrs[src]; - dst++; - } - } - *numTagsPtr = dst; - ckfree((char *) tagInfo.counts); - if (dst == 0) { - ckfree((char *) tagInfo.tagPtrs); - return NULL; - } - return tagInfo.tagPtrs; -} - -/* - *---------------------------------------------------------------------- - * - * IncCount -- - * - * This is a utility procedure used by TkBTreeGetTags. It - * increments the count for a particular tag, adding a new - * entry for that tag if there wasn't one previously. - * - * Results: - * None. - * - * Side effects: - * The information at *tagInfoPtr may be modified, and the arrays - * may be reallocated to make them larger. - * - *---------------------------------------------------------------------- - */ - -static void -IncCount(tagPtr, inc, tagInfoPtr) - TkTextTag *tagPtr; /* Handle for tag. */ - int inc; /* Amount by which to increment tag count. */ - TagInfo *tagInfoPtr; /* Holds cumulative information about tags; - * increment count here. */ -{ - register TkTextTag **tagPtrPtr; - int count; - - for (tagPtrPtr = tagInfoPtr->tagPtrs, count = tagInfoPtr->numTags; - count > 0; tagPtrPtr++, count--) { - if (*tagPtrPtr == tagPtr) { - tagInfoPtr->counts[tagInfoPtr->numTags-count] += inc; - return; - } - } - - /* - * There isn't currently an entry for this tag, so we have to - * make a new one. If the arrays are full, then enlarge the - * arrays first. - */ - - if (tagInfoPtr->numTags == tagInfoPtr->arraySize) { - TkTextTag **newTags; - int *newCounts, newSize; - - newSize = 2*tagInfoPtr->arraySize; - newTags = (TkTextTag **) ckalloc((unsigned) - (newSize*sizeof(TkTextTag *))); - memcpy((VOID *) newTags, (VOID *) tagInfoPtr->tagPtrs, - tagInfoPtr->arraySize * sizeof(TkTextTag *)); - ckfree((char *) tagInfoPtr->tagPtrs); - tagInfoPtr->tagPtrs = newTags; - newCounts = (int *) ckalloc((unsigned) (newSize*sizeof(int))); - memcpy((VOID *) newCounts, (VOID *) tagInfoPtr->counts, - tagInfoPtr->arraySize * sizeof(int)); - ckfree((char *) tagInfoPtr->counts); - tagInfoPtr->counts = newCounts; - tagInfoPtr->arraySize = newSize; - } - - tagInfoPtr->tagPtrs[tagInfoPtr->numTags] = tagPtr; - tagInfoPtr->counts[tagInfoPtr->numTags] = inc; - tagInfoPtr->numTags++; -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeCheck -- - * - * This procedure runs a set of consistency checks over a B-tree - * and panics if any inconsistencies are found. - * - * Results: - * None. - * - * Side effects: - * If a structural defect is found, the procedure panics with an - * error message. - * - *---------------------------------------------------------------------- - */ - -void -TkBTreeCheck(tree) - TkTextBTree tree; /* Tree to check. */ -{ - BTree *treePtr = (BTree *) tree; - register Summary *summaryPtr; - register Node *nodePtr; - register TkTextLine *linePtr; - register TkTextSegment *segPtr; - register TkTextTag *tagPtr; - Tcl_HashEntry *entryPtr; - Tcl_HashSearch search; - int count; - - /* - * Make sure that the tag toggle counts and the tag root pointers are OK. - */ - for (entryPtr = Tcl_FirstHashEntry(&treePtr->textPtr->tagTable, &search); - entryPtr != NULL ; entryPtr = Tcl_NextHashEntry(&search)) { - tagPtr = (TkTextTag *) Tcl_GetHashValue(entryPtr); - nodePtr = tagPtr->tagRootPtr; - if (nodePtr == (Node *) NULL) { - if (tagPtr->toggleCount != 0) { - panic("TkBTreeCheck found \"%s\" with toggles (%d) but no root", - tagPtr->name, tagPtr->toggleCount); - } - continue; /* no ranges for the tag */ - } else if (tagPtr->toggleCount == 0) { - panic("TkBTreeCheck found root for \"%s\" with no toggles", - tagPtr->name); - } else if (tagPtr->toggleCount & 1) { - panic("TkBTreeCheck found odd toggle count for \"%s\" (%d)", - tagPtr->name, tagPtr->toggleCount); - } - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - panic("TkBTreeCheck found root node with summary info"); - } - } - count = 0; - if (nodePtr->level > 0) { - for (nodePtr = nodePtr->children.nodePtr ; nodePtr != NULL ; - nodePtr = nodePtr->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr == tagPtr) { - count += summaryPtr->toggleCount; - } - } - } - } else { - for (linePtr = nodePtr->children.linePtr ; linePtr != NULL ; - linePtr = linePtr->nextPtr) { - for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if ((segPtr->typePtr == &tkTextToggleOnType || - segPtr->typePtr == &tkTextToggleOffType) && - segPtr->body.toggle.tagPtr == tagPtr) { - count++; - } - } - } - } - if (count != tagPtr->toggleCount) { - panic("TkBTreeCheck toggleCount (%d) wrong for \"%s\" should be (%d)", - tagPtr->toggleCount, tagPtr->name, count); - } - } - - /* - * Call a recursive procedure to do the main body of checks. - */ - - nodePtr = treePtr->rootPtr; - CheckNodeConsistency(treePtr->rootPtr); - - /* - * Make sure that there are at least two lines in the text and - * that the last line has no characters except a newline. - */ - - if (nodePtr->numLines < 2) { - panic("TkBTreeCheck: less than 2 lines in tree"); - } - while (nodePtr->level > 0) { - nodePtr = nodePtr->children.nodePtr; - while (nodePtr->nextPtr != NULL) { - nodePtr = nodePtr->nextPtr; - } - } - linePtr = nodePtr->children.linePtr; - while (linePtr->nextPtr != NULL) { - linePtr = linePtr->nextPtr; - } - segPtr = linePtr->segPtr; - while ((segPtr->typePtr == &tkTextToggleOffType) - || (segPtr->typePtr == &tkTextRightMarkType) - || (segPtr->typePtr == &tkTextLeftMarkType)) { - /* - * It's OK to toggle a tag off in the last line, but - * not to start a new range. It's also OK to have marks - * in the last line. - */ - - segPtr = segPtr->nextPtr; - } - if (segPtr->typePtr != &tkTextCharType) { - panic("TkBTreeCheck: last line has bogus segment type"); - } - if (segPtr->nextPtr != NULL) { - panic("TkBTreeCheck: last line has too many segments"); - } - if (segPtr->size != 1) { - panic("TkBTreeCheck: last line has wrong # characters: %d", - segPtr->size); - } - if ((segPtr->body.chars[0] != '\n') || (segPtr->body.chars[1] != 0)) { - panic("TkBTreeCheck: last line had bad value: %s", - segPtr->body.chars); - } -} - -/* - *---------------------------------------------------------------------- - * - * CheckNodeConsistency -- - * - * This procedure is called as part of consistency checking for - * B-trees: it checks several aspects of a node and also runs - * checks recursively on the node's children. - * - * Results: - * None. - * - * Side effects: - * If anything suspicious is found in the tree structure, the - * procedure panics. - * - *---------------------------------------------------------------------- - */ - -static void -CheckNodeConsistency(nodePtr) - register Node *nodePtr; /* Node whose subtree should be - * checked. */ -{ - register Node *childNodePtr; - register Summary *summaryPtr, *summaryPtr2; - register TkTextLine *linePtr; - register TkTextSegment *segPtr; - int numChildren, numLines, toggleCount, minChildren; - - if (nodePtr->parentPtr != NULL) { - minChildren = MIN_CHILDREN; - } else if (nodePtr->level > 0) { - minChildren = 2; - } else { - minChildren = 1; - } - if ((nodePtr->numChildren < minChildren) - || (nodePtr->numChildren > MAX_CHILDREN)) { - panic("CheckNodeConsistency: bad child count (%d)", - nodePtr->numChildren); - } - - numChildren = 0; - numLines = 0; - if (nodePtr->level == 0) { - for (linePtr = nodePtr->children.linePtr; linePtr != NULL; - linePtr = linePtr->nextPtr) { - if (linePtr->parentPtr != nodePtr) { - panic("CheckNodeConsistency: line doesn't point to parent"); - } - if (linePtr->segPtr == NULL) { - panic("CheckNodeConsistency: line has no segments"); - } - for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr->checkProc != NULL) { - (*segPtr->typePtr->checkProc)(segPtr, linePtr); - } - if ((segPtr->size == 0) && (!segPtr->typePtr->leftGravity) - && (segPtr->nextPtr != NULL) - && (segPtr->nextPtr->size == 0) - && (segPtr->nextPtr->typePtr->leftGravity)) { - panic("CheckNodeConsistency: wrong segment order for gravity"); - } - if ((segPtr->nextPtr == NULL) - && (segPtr->typePtr != &tkTextCharType)) { - panic("CheckNodeConsistency: line ended with wrong type"); - } - } - numChildren++; - numLines++; - } - } else { - for (childNodePtr = nodePtr->children.nodePtr; childNodePtr != NULL; - childNodePtr = childNodePtr->nextPtr) { - if (childNodePtr->parentPtr != nodePtr) { - panic("CheckNodeConsistency: node doesn't point to parent"); - } - if (childNodePtr->level != (nodePtr->level-1)) { - panic("CheckNodeConsistency: level mismatch (%d %d)", - nodePtr->level, childNodePtr->level); - } - CheckNodeConsistency(childNodePtr); - for (summaryPtr = childNodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - for (summaryPtr2 = nodePtr->summaryPtr; ; - summaryPtr2 = summaryPtr2->nextPtr) { - if (summaryPtr2 == NULL) { - if (summaryPtr->tagPtr->tagRootPtr == nodePtr) { - break; - } - panic("CheckNodeConsistency: node tag \"%s\" not %s", - summaryPtr->tagPtr->name, - "present in parent summaries"); - } - if (summaryPtr->tagPtr == summaryPtr2->tagPtr) { - break; - } - } - } - numChildren++; - numLines += childNodePtr->numLines; - } - } - if (numChildren != nodePtr->numChildren) { - panic("CheckNodeConsistency: mismatch in numChildren (%d %d)", - numChildren, nodePtr->numChildren); - } - if (numLines != nodePtr->numLines) { - panic("CheckNodeConsistency: mismatch in numLines (%d %d)", - numLines, nodePtr->numLines); - } - - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr->tagPtr->toggleCount == summaryPtr->toggleCount) { - panic("CheckNodeConsistency: found unpruned root for \"%s\"", - summaryPtr->tagPtr->name); - } - toggleCount = 0; - if (nodePtr->level == 0) { - for (linePtr = nodePtr->children.linePtr; linePtr != NULL; - linePtr = linePtr->nextPtr) { - for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if ((segPtr->typePtr != &tkTextToggleOnType) - && (segPtr->typePtr != &tkTextToggleOffType)) { - continue; - } - if (segPtr->body.toggle.tagPtr == summaryPtr->tagPtr) { - toggleCount ++; - } - } - } - } else { - for (childNodePtr = nodePtr->children.nodePtr; - childNodePtr != NULL; - childNodePtr = childNodePtr->nextPtr) { - for (summaryPtr2 = childNodePtr->summaryPtr; - summaryPtr2 != NULL; - summaryPtr2 = summaryPtr2->nextPtr) { - if (summaryPtr2->tagPtr == summaryPtr->tagPtr) { - toggleCount += summaryPtr2->toggleCount; - } - } - } - } - if (toggleCount != summaryPtr->toggleCount) { - panic("CheckNodeConsistency: mismatch in toggleCount (%d %d)", - toggleCount, summaryPtr->toggleCount); - } - for (summaryPtr2 = summaryPtr->nextPtr; summaryPtr2 != NULL; - summaryPtr2 = summaryPtr2->nextPtr) { - if (summaryPtr2->tagPtr == summaryPtr->tagPtr) { - panic("CheckNodeConsistency: duplicated node tag: %s", - summaryPtr->tagPtr->name); - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * Rebalance -- - * - * This procedure is called when a node of a B-tree appears to be - * out of balance (too many children, or too few). It rebalances - * that node and all of its ancestors in the tree. - * - * Results: - * None. - * - * Side effects: - * The internal structure of treePtr may change. - * - *---------------------------------------------------------------------- - */ - -static void -Rebalance(treePtr, nodePtr) - BTree *treePtr; /* Tree that is being rebalanced. */ - register Node *nodePtr; /* Node that may be out of balance. */ -{ - /* - * Loop over the entire ancestral chain of the node, working up - * through the tree one node at a time until the root node has - * been processed. - */ - - for ( ; nodePtr != NULL; nodePtr = nodePtr->parentPtr) { - register Node *newPtr, *childPtr; - register TkTextLine *linePtr; - int i; - - /* - * Check to see if the node has too many children. If it does, - * then split off all but the first MIN_CHILDREN into a separate - * node following the original one. Then repeat until the - * node has a decent size. - */ - - if (nodePtr->numChildren > MAX_CHILDREN) { - while (1) { - /* - * If the node being split is the root node, then make a - * new root node above it first. - */ - - if (nodePtr->parentPtr == NULL) { - newPtr = (Node *) ckalloc(sizeof(Node)); - newPtr->parentPtr = NULL; - newPtr->nextPtr = NULL; - newPtr->summaryPtr = NULL; - newPtr->level = nodePtr->level + 1; - newPtr->children.nodePtr = nodePtr; - newPtr->numChildren = 1; - newPtr->numLines = nodePtr->numLines; - RecomputeNodeCounts(newPtr); - treePtr->rootPtr = newPtr; - } - newPtr = (Node *) ckalloc(sizeof(Node)); - newPtr->parentPtr = nodePtr->parentPtr; - newPtr->nextPtr = nodePtr->nextPtr; - nodePtr->nextPtr = newPtr; - newPtr->summaryPtr = NULL; - newPtr->level = nodePtr->level; - newPtr->numChildren = nodePtr->numChildren - MIN_CHILDREN; - if (nodePtr->level == 0) { - for (i = MIN_CHILDREN-1, - linePtr = nodePtr->children.linePtr; - i > 0; i--, linePtr = linePtr->nextPtr) { - /* Empty loop body. */ - } - newPtr->children.linePtr = linePtr->nextPtr; - linePtr->nextPtr = NULL; - } else { - for (i = MIN_CHILDREN-1, - childPtr = nodePtr->children.nodePtr; - i > 0; i--, childPtr = childPtr->nextPtr) { - /* Empty loop body. */ - } - newPtr->children.nodePtr = childPtr->nextPtr; - childPtr->nextPtr = NULL; - } - RecomputeNodeCounts(nodePtr); - nodePtr->parentPtr->numChildren++; - nodePtr = newPtr; - if (nodePtr->numChildren <= MAX_CHILDREN) { - RecomputeNodeCounts(nodePtr); - break; - } - } - } - - while (nodePtr->numChildren < MIN_CHILDREN) { - register Node *otherPtr; - Node *halfwayNodePtr = NULL; /* Initialization needed only */ - TkTextLine *halfwayLinePtr = NULL; /* to prevent cc warnings. */ - int totalChildren, firstChildren, i; - - /* - * Too few children for this node. If this is the root then, - * it's OK for it to have less than MIN_CHILDREN children - * as long as it's got at least two. If it has only one - * (and isn't at level 0), then chop the root node out of - * the tree and use its child as the new root. - */ - - if (nodePtr->parentPtr == NULL) { - if ((nodePtr->numChildren == 1) && (nodePtr->level > 0)) { - treePtr->rootPtr = nodePtr->children.nodePtr; - treePtr->rootPtr->parentPtr = NULL; - DeleteSummaries(nodePtr->summaryPtr); - ckfree((char *) nodePtr); - } - return; - } - - /* - * Not the root. Make sure that there are siblings to - * balance with. - */ - - if (nodePtr->parentPtr->numChildren < 2) { - Rebalance(treePtr, nodePtr->parentPtr); - continue; - } - - /* - * Find a sibling neighbor to borrow from, and arrange for - * nodePtr to be the earlier of the pair. - */ - - if (nodePtr->nextPtr == NULL) { - for (otherPtr = nodePtr->parentPtr->children.nodePtr; - otherPtr->nextPtr != nodePtr; - otherPtr = otherPtr->nextPtr) { - /* Empty loop body. */ - } - nodePtr = otherPtr; - } - otherPtr = nodePtr->nextPtr; - - /* - * We're going to either merge the two siblings together - * into one node or redivide the children among them to - * balance their loads. As preparation, join their two - * child lists into a single list and remember the half-way - * point in the list. - */ - - totalChildren = nodePtr->numChildren + otherPtr->numChildren; - firstChildren = totalChildren/2; - if (nodePtr->children.nodePtr == NULL) { - nodePtr->children = otherPtr->children; - otherPtr->children.nodePtr = NULL; - otherPtr->children.linePtr = NULL; - } - if (nodePtr->level == 0) { - register TkTextLine *linePtr; - - for (linePtr = nodePtr->children.linePtr, i = 1; - linePtr->nextPtr != NULL; - linePtr = linePtr->nextPtr, i++) { - if (i == firstChildren) { - halfwayLinePtr = linePtr; - } - } - linePtr->nextPtr = otherPtr->children.linePtr; - while (i <= firstChildren) { - halfwayLinePtr = linePtr; - linePtr = linePtr->nextPtr; - i++; - } - } else { - register Node *childPtr; - - for (childPtr = nodePtr->children.nodePtr, i = 1; - childPtr->nextPtr != NULL; - childPtr = childPtr->nextPtr, i++) { - if (i <= firstChildren) { - if (i == firstChildren) { - halfwayNodePtr = childPtr; - } - } - } - childPtr->nextPtr = otherPtr->children.nodePtr; - while (i <= firstChildren) { - halfwayNodePtr = childPtr; - childPtr = childPtr->nextPtr; - i++; - } - } - - /* - * If the two siblings can simply be merged together, do it. - */ - - if (totalChildren <= MAX_CHILDREN) { - RecomputeNodeCounts(nodePtr); - nodePtr->nextPtr = otherPtr->nextPtr; - nodePtr->parentPtr->numChildren--; - DeleteSummaries(otherPtr->summaryPtr); - ckfree((char *) otherPtr); - continue; - } - - /* - * The siblings can't be merged, so just divide their - * children evenly between them. - */ - - if (nodePtr->level == 0) { - otherPtr->children.linePtr = halfwayLinePtr->nextPtr; - halfwayLinePtr->nextPtr = NULL; - } else { - otherPtr->children.nodePtr = halfwayNodePtr->nextPtr; - halfwayNodePtr->nextPtr = NULL; - } - RecomputeNodeCounts(nodePtr); - RecomputeNodeCounts(otherPtr); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * RecomputeNodeCounts -- - * - * This procedure is called to recompute all the counts in a node - * (tags, child information, etc.) by scanning the information in - * its descendants. This procedure is called during rebalancing - * when a node's child structure has changed. - * - * Results: - * None. - * - * Side effects: - * The tag counts for nodePtr are modified to reflect its current - * child structure, as are its numChildren and numLines fields. - * Also, all of the childrens' parentPtr fields are made to point - * to nodePtr. - * - *---------------------------------------------------------------------- - */ - -static void -RecomputeNodeCounts(nodePtr) - register Node *nodePtr; /* Node whose tag summary information - * must be recomputed. */ -{ - register Summary *summaryPtr, *summaryPtr2; - register Node *childPtr; - register TkTextLine *linePtr; - register TkTextSegment *segPtr; - TkTextTag *tagPtr; - - /* - * Zero out all the existing counts for the node, but don't delete - * the existing Summary records (most of them will probably be reused). - */ - - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; - summaryPtr = summaryPtr->nextPtr) { - summaryPtr->toggleCount = 0; - } - nodePtr->numChildren = 0; - nodePtr->numLines = 0; - - /* - * Scan through the children, adding the childrens' tag counts into - * the node's tag counts and adding new Summary structures if - * necessary. - */ - - if (nodePtr->level == 0) { - for (linePtr = nodePtr->children.linePtr; linePtr != NULL; - linePtr = linePtr->nextPtr) { - nodePtr->numChildren++; - nodePtr->numLines++; - linePtr->parentPtr = nodePtr; - for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (((segPtr->typePtr != &tkTextToggleOnType) - && (segPtr->typePtr != &tkTextToggleOffType)) - || !(segPtr->body.toggle.inNodeCounts)) { - continue; - } - tagPtr = segPtr->body.toggle.tagPtr; - for (summaryPtr = nodePtr->summaryPtr; ; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr == NULL) { - summaryPtr = (Summary *) ckalloc(sizeof(Summary)); - summaryPtr->tagPtr = tagPtr; - summaryPtr->toggleCount = 1; - summaryPtr->nextPtr = nodePtr->summaryPtr; - nodePtr->summaryPtr = summaryPtr; - break; - } - if (summaryPtr->tagPtr == tagPtr) { - summaryPtr->toggleCount++; - break; - } - } - } - } - } else { - for (childPtr = nodePtr->children.nodePtr; childPtr != NULL; - childPtr = childPtr->nextPtr) { - nodePtr->numChildren++; - nodePtr->numLines += childPtr->numLines; - childPtr->parentPtr = nodePtr; - for (summaryPtr2 = childPtr->summaryPtr; summaryPtr2 != NULL; - summaryPtr2 = summaryPtr2->nextPtr) { - for (summaryPtr = nodePtr->summaryPtr; ; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr == NULL) { - summaryPtr = (Summary *) ckalloc(sizeof(Summary)); - summaryPtr->tagPtr = summaryPtr2->tagPtr; - summaryPtr->toggleCount = summaryPtr2->toggleCount; - summaryPtr->nextPtr = nodePtr->summaryPtr; - nodePtr->summaryPtr = summaryPtr; - break; - } - if (summaryPtr->tagPtr == summaryPtr2->tagPtr) { - summaryPtr->toggleCount += summaryPtr2->toggleCount; - break; - } - } - } - } - } - - /* - * Scan through the node's tag records again and delete any Summary - * records that still have a zero count, or that have all the toggles. - * The node with the children that account for all the tags toggles - * have no summary information, and they become the tagRootPtr for the tag. - */ - - summaryPtr2 = NULL; - for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; ) { - if (summaryPtr->toggleCount > 0 && - summaryPtr->toggleCount < summaryPtr->tagPtr->toggleCount) { - if (nodePtr->level == summaryPtr->tagPtr->tagRootPtr->level) { - /* - * The tag's root node split and some toggles left. - * The tag root must move up a level. - */ - summaryPtr->tagPtr->tagRootPtr = nodePtr->parentPtr; - } - summaryPtr2 = summaryPtr; - summaryPtr = summaryPtr->nextPtr; - continue; - } - if (summaryPtr->toggleCount == summaryPtr->tagPtr->toggleCount) { - /* - * A node merge has collected all the toggles under one node. - * Push the root down to this level. - */ - summaryPtr->tagPtr->tagRootPtr = nodePtr; - } - if (summaryPtr2 != NULL) { - summaryPtr2->nextPtr = summaryPtr->nextPtr; - ckfree((char *) summaryPtr); - summaryPtr = summaryPtr2->nextPtr; - } else { - nodePtr->summaryPtr = summaryPtr->nextPtr; - ckfree((char *) summaryPtr); - summaryPtr = nodePtr->summaryPtr; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeNumLines -- - * - * This procedure returns a count of the number of lines of - * text present in a given B-tree. - * - * Results: - * The return value is a count of the number of usable lines - * in tree (i.e. it doesn't include the dummy line that is just - * used to mark the end of the tree). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeNumLines(tree) - TkTextBTree tree; /* Information about tree. */ -{ - BTree *treePtr = (BTree *) tree; - return treePtr->rootPtr->numLines - 1; -} - -/* - *-------------------------------------------------------------- - * - * CharSplitProc -- - * - * This procedure implements splitting for character segments. - * - * Results: - * The return value is a pointer to a chain of two segments - * that have the same characters as segPtr except split - * among the two segments. - * - * Side effects: - * Storage for segPtr is freed. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -CharSplitProc(segPtr, index) - TkTextSegment *segPtr; /* Pointer to segment to split. */ - int index; /* Position within segment at which - * to split. */ -{ - TkTextSegment *newPtr1, *newPtr2; - - newPtr1 = (TkTextSegment *) ckalloc(CSEG_SIZE(index)); - newPtr2 = (TkTextSegment *) ckalloc( - CSEG_SIZE(segPtr->size - index)); - newPtr1->typePtr = &tkTextCharType; - newPtr1->nextPtr = newPtr2; - newPtr1->size = index; - strncpy(newPtr1->body.chars, segPtr->body.chars, (size_t) index); - newPtr1->body.chars[index] = 0; - newPtr2->typePtr = &tkTextCharType; - newPtr2->nextPtr = segPtr->nextPtr; - newPtr2->size = segPtr->size - index; - strcpy(newPtr2->body.chars, segPtr->body.chars + index); - ckfree((char*) segPtr); - return newPtr1; -} - -/* - *-------------------------------------------------------------- - * - * CharCleanupProc -- - * - * This procedure merges adjacent character segments into - * a single character segment, if possible. - * - * Results: - * The return value is a pointer to the first segment in - * the (new) list of segments that used to start with segPtr. - * - * Side effects: - * Storage for the segments may be allocated and freed. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static TkTextSegment * -CharCleanupProc(segPtr, linePtr) - TkTextSegment *segPtr; /* Pointer to first of two adjacent - * segments to join. */ - TkTextLine *linePtr; /* Line containing segments (not - * used). */ -{ - TkTextSegment *segPtr2, *newPtr; - - segPtr2 = segPtr->nextPtr; - if ((segPtr2 == NULL) || (segPtr2->typePtr != &tkTextCharType)) { - return segPtr; - } - newPtr = (TkTextSegment *) ckalloc(CSEG_SIZE( - segPtr->size + segPtr2->size)); - newPtr->typePtr = &tkTextCharType; - newPtr->nextPtr = segPtr2->nextPtr; - newPtr->size = segPtr->size + segPtr2->size; - strcpy(newPtr->body.chars, segPtr->body.chars); - strcpy(newPtr->body.chars + segPtr->size, segPtr2->body.chars); - ckfree((char*) segPtr); - ckfree((char*) segPtr2); - return newPtr; -} - -/* - *-------------------------------------------------------------- - * - * CharDeleteProc -- - * - * This procedure is invoked to delete a character segment. - * - * Results: - * Always returns 0 to indicate that the segment was deleted. - * - * Side effects: - * Storage for the segment is freed. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -CharDeleteProc(segPtr, linePtr, treeGone) - TkTextSegment *segPtr; /* Segment to delete. */ - TkTextLine *linePtr; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ -{ - ckfree((char*) segPtr); - return 0; -} - -/* - *-------------------------------------------------------------- - * - * CharCheckProc -- - * - * This procedure is invoked to perform consistency checks - * on character segments. - * - * Results: - * None. - * - * Side effects: - * If the segment isn't inconsistent then the procedure - * panics. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -CharCheckProc(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ -{ - /* - * Make sure that the segment contains the number of - * characters indicated by its header, and that the last - * segment in a line ends in a newline. Also make sure - * that there aren't ever two character segments adjacent - * to each other: they should be merged together. - */ - - if (segPtr->size <= 0) { - panic("CharCheckProc: segment has size <= 0"); - } - if (strlen(segPtr->body.chars) != (size_t) segPtr->size) { - panic("CharCheckProc: segment has wrong size"); - } - if (segPtr->nextPtr == NULL) { - if (segPtr->body.chars[segPtr->size-1] != '\n') { - panic("CharCheckProc: line doesn't end with newline"); - } - } else { - if (segPtr->nextPtr->typePtr == &tkTextCharType) { - panic("CharCheckProc: adjacent character segments weren't merged"); - } - } -} - -/* - *-------------------------------------------------------------- - * - * ToggleDeleteProc -- - * - * This procedure is invoked to delete toggle segments. - * - * Results: - * Returns 1 to indicate that the segment may not be deleted, - * unless the entire B-tree is going away. - * - * Side effects: - * If the tree is going away then the toggle's memory is - * freed; otherwise the toggle counts in nodes above the - * segment get updated. - * - *-------------------------------------------------------------- - */ - -static int -ToggleDeleteProc(segPtr, linePtr, treeGone) - TkTextSegment *segPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ -{ - if (treeGone) { - ckfree((char *) segPtr); - return 0; - } - - /* - * This toggle is in the middle of a range of characters that's - * being deleted. Refuse to die. We'll be moved to the end of - * the deleted range and our cleanup procedure will be called - * later. Decrement node toggle counts here, and set a flag - * so we'll re-increment them in the cleanup procedure. - */ - - if (segPtr->body.toggle.inNodeCounts) { - ChangeNodeToggleCount(linePtr->parentPtr, - segPtr->body.toggle.tagPtr, -1); - segPtr->body.toggle.inNodeCounts = 0; - } - return 1; -} - -/* - *-------------------------------------------------------------- - * - * ToggleCleanupProc -- - * - * This procedure is called when a toggle is part of a line that's - * been modified in some way. It's invoked after the - * modifications are complete. - * - * Results: - * The return value is the head segment in a new list - * that is to replace the tail of the line that used to - * start at segPtr. This allows the procedure to delete - * or modify segPtr. - * - * Side effects: - * Toggle counts in the nodes above the new line will be - * updated if they're not already. Toggles may be collapsed - * if there are duplicate toggles at the same position. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -ToggleCleanupProc(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line that now contains segment. */ -{ - TkTextSegment *segPtr2, *prevPtr; - int counts; - - /* - * If this is a toggle-off segment, look ahead through the next - * segments to see if there's a toggle-on segment for the same tag - * before any segments with non-zero size. If so then the two - * toggles cancel each other; remove them both. - */ - - if (segPtr->typePtr == &tkTextToggleOffType) { - for (prevPtr = segPtr, segPtr2 = prevPtr->nextPtr; - (segPtr2 != NULL) && (segPtr2->size == 0); - prevPtr = segPtr2, segPtr2 = prevPtr->nextPtr) { - if (segPtr2->typePtr != &tkTextToggleOnType) { - continue; - } - if (segPtr2->body.toggle.tagPtr != segPtr->body.toggle.tagPtr) { - continue; - } - counts = segPtr->body.toggle.inNodeCounts - + segPtr2->body.toggle.inNodeCounts; - if (counts != 0) { - ChangeNodeToggleCount(linePtr->parentPtr, - segPtr->body.toggle.tagPtr, -counts); - } - prevPtr->nextPtr = segPtr2->nextPtr; - ckfree((char *) segPtr2); - segPtr2 = segPtr->nextPtr; - ckfree((char *) segPtr); - return segPtr2; - } - } - - if (!segPtr->body.toggle.inNodeCounts) { - ChangeNodeToggleCount(linePtr->parentPtr, - segPtr->body.toggle.tagPtr, 1); - segPtr->body.toggle.inNodeCounts = 1; - } - return segPtr; -} - -/* - *-------------------------------------------------------------- - * - * ToggleLineChangeProc -- - * - * This procedure is invoked when a toggle segment is about - * to move from one line to another. - * - * Results: - * None. - * - * Side effects: - * Toggle counts are decremented in the nodes above the line. - * - *-------------------------------------------------------------- - */ - -static void -ToggleLineChangeProc(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line that used to contain segment. */ -{ - if (segPtr->body.toggle.inNodeCounts) { - ChangeNodeToggleCount(linePtr->parentPtr, - segPtr->body.toggle.tagPtr, -1); - segPtr->body.toggle.inNodeCounts = 0; - } -} - -/* - *-------------------------------------------------------------- - * - * ToggleCheckProc -- - * - * This procedure is invoked to perform consistency checks - * on toggle segments. - * - * Results: - * None. - * - * Side effects: - * If a consistency problem is found the procedure panics. - * - *-------------------------------------------------------------- - */ - -static void -ToggleCheckProc(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ -{ - register Summary *summaryPtr; - int needSummary; - - if (segPtr->size != 0) { - panic("ToggleCheckProc: segment had non-zero size"); - } - if (!segPtr->body.toggle.inNodeCounts) { - panic("ToggleCheckProc: toggle counts not updated in nodes"); - } - needSummary = (segPtr->body.toggle.tagPtr->tagRootPtr != linePtr->parentPtr); - for (summaryPtr = linePtr->parentPtr->summaryPtr; ; - summaryPtr = summaryPtr->nextPtr) { - if (summaryPtr == NULL) { - if (needSummary) { - panic("ToggleCheckProc: tag not present in node"); - } else { - break; - } - } - if (summaryPtr->tagPtr == segPtr->body.toggle.tagPtr) { - if (!needSummary) { - panic("ToggleCheckProc: tag present in root node summary"); - } - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkBTreeCharsInLine -- - * - * This procedure returns a count of the number of characters - * in a given line. - * - * Results: - * The return value is the character count for linePtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeCharsInLine(linePtr) - TkTextLine *linePtr; /* Line whose characters should be - * counted. */ -{ - TkTextSegment *segPtr; - int count; - - count = 0; - for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { - count += segPtr->size; - } - return count; -} diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c deleted file mode 100644 index 8d8de8d..0000000 --- a/generic/tkTextDisp.c +++ /dev/null @@ -1,5015 +0,0 @@ -/* - * tkTextDisp.c -- - * - * This module provides facilities to display text widgets. It is - * the only place where information is kept about the screen layout - * of text widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextDisp.c,v 1.2 1998/09/14 18:23:18 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" -#include "tkText.h" - -/* - * The following structure describes how to display a range of characters. - * The information is generated by scanning all of the tags associated - * with the characters and combining that with default information for - * the overall widget. These structures form the hash keys for - * dInfoPtr->styleTable. - */ - -typedef struct StyleValues { - Tk_3DBorder border; /* Used for drawing background under text. - * NULL means use widget background. */ - int borderWidth; /* Width of 3-D border for background. */ - int relief; /* 3-D relief for background. */ - Pixmap bgStipple; /* Stipple bitmap for background. None - * means draw solid. */ - XColor *fgColor; /* Foreground color for text. */ - Tk_Font tkfont; /* Font for displaying text. */ - Pixmap fgStipple; /* Stipple bitmap for text and other - * foreground stuff. None means draw - * solid.*/ - int justify; /* Justification style for text. */ - int lMargin1; /* Left margin, in pixels, for first display - * line of each text line. */ - int lMargin2; /* Left margin, in pixels, for second and - * later display lines of each text line. */ - int offset; /* Offset in pixels of baseline, relative to - * baseline of line. */ - int overstrike; /* Non-zero means draw overstrike through - * text. */ - int rMargin; /* Right margin, in pixels. */ - int spacing1; /* Spacing above first dline in text line. */ - int spacing2; /* Spacing between lines of dline. */ - int spacing3; /* Spacing below last dline in text line. */ - TkTextTabArray *tabArrayPtr;/* Locations and types of tab stops (may - * be NULL). */ - int underline; /* Non-zero means draw underline underneath - * text. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * One of tkTextCharUid, tkTextNoneUid, - * or tkTextWordUid. */ -} StyleValues; - -/* - * The following structure extends the StyleValues structure above with - * graphics contexts used to actually draw the characters. The entries - * in dInfoPtr->styleTable point to structures of this type. - */ - -typedef struct TextStyle { - int refCount; /* Number of times this structure is - * referenced in Chunks. */ - GC bgGC; /* Graphics context for background. None - * means use widget background. */ - GC fgGC; /* Graphics context for foreground. */ - StyleValues *sValuePtr; /* Raw information from which GCs were - * derived. */ - Tcl_HashEntry *hPtr; /* Pointer to entry in styleTable. Used - * to delete entry. */ -} TextStyle; - -/* - * The following macro determines whether two styles have the same - * background so that, for example, no beveled border should be drawn - * between them. - */ - -#define SAME_BACKGROUND(s1, s2) \ - (((s1)->sValuePtr->border == (s2)->sValuePtr->border) \ - && ((s1)->sValuePtr->borderWidth == (s2)->sValuePtr->borderWidth) \ - && ((s1)->sValuePtr->relief == (s2)->sValuePtr->relief) \ - && ((s1)->sValuePtr->bgStipple == (s2)->sValuePtr->bgStipple)) - -/* - * The following structure describes one line of the display, which may - * be either part or all of one line of the text. - */ - -typedef struct DLine { - TkTextIndex index; /* Identifies first character in text - * that is displayed on this line. */ - int count; /* Number of characters accounted for by this - * display line, including a trailing space - * or newline that isn't actually displayed. */ - int y; /* Y-position at which line is supposed to - * be drawn (topmost pixel of rectangular - * area occupied by line). */ - int oldY; /* Y-position at which line currently - * appears on display. -1 means line isn't - * currently visible on display and must be - * redrawn. This is used to move lines by - * scrolling rather than re-drawing. */ - int height; /* Height of line, in pixels. */ - int baseline; /* Offset of text baseline from y, in - * pixels. */ - int spaceAbove; /* How much extra space was added to the - * top of the line because of spacing - * options. This is included in height - * and baseline. */ - int spaceBelow; /* How much extra space was added to the - * bottom of the line because of spacing - * options. This is included in height. */ - int length; /* Total length of line, in pixels. */ - TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all - * of those that are displayed on this - * line of the screen. */ - struct DLine *nextPtr; /* Next in list of all display lines for - * this window. The list is sorted in - * order from top to bottom. Note: the - * next DLine doesn't always correspond - * to the next line of text: (a) can have - * multiple DLines for one text line, and - * (b) can have gaps where DLine's have been - * deleted because they're out of date. */ - int flags; /* Various flag bits: see below for values. */ -} DLine; - -/* - * Flag bits for DLine structures: - * - * HAS_3D_BORDER - Non-zero means that at least one of the - * chunks in this line has a 3D border, so - * it potentially interacts with 3D borders - * in neighboring lines (see - * DisplayLineBackground). - * NEW_LAYOUT - Non-zero means that the line has been - * re-layed out since the last time the - * display was updated. - * TOP_LINE - Non-zero means that this was the top line - * in the window the last time that the window - * was laid out. This is important because - * a line may be displayed differently if its - * at the top or bottom than if it's in the - * middle (e.g. beveled edges aren't displayed - * for middle lines if the adjacent line has - * a similar background). - * BOTTOM_LINE - Non-zero means that this was the bottom line - * in the window the last time that the window - * was laid out. - */ - -#define HAS_3D_BORDER 1 -#define NEW_LAYOUT 2 -#define TOP_LINE 4 -#define BOTTOM_LINE 8 - -/* - * Overall display information for a text widget: - */ - -typedef struct TextDInfo { - Tcl_HashTable styleTable; /* Hash table that maps from StyleValues - * to TextStyles for this widget. */ - DLine *dLinePtr; /* First in list of all display lines for - * this widget, in order from top to bottom. */ - GC copyGC; /* Graphics context for copying from off- - * screen pixmaps onto screen. */ - GC scrollGC; /* Graphics context for copying from one place - * in the window to another (scrolling): - * differs from copyGC in that we need to get - * GraphicsExpose events. */ - int x; /* First x-coordinate that may be used for - * actually displaying line information. - * Leaves space for border, etc. */ - int y; /* First y-coordinate that may be used for - * actually displaying line information. - * Leaves space for border, etc. */ - int maxX; /* First x-coordinate to right of available - * space for displaying lines. */ - int maxY; /* First y-coordinate below available - * space for displaying lines. */ - int topOfEof; /* Top-most pixel (lowest y-value) that has - * been drawn in the appropriate fashion for - * the portion of the window after the last - * line of the text. This field is used to - * figure out when to redraw part or all of - * the eof field. */ - - /* - * Information used for scrolling: - */ - - int newCharOffset; /* Desired x scroll position, measured as the - * number of average-size characters off-screen - * to the left for a line with no left - * margin. */ - int curPixelOffset; /* Actual x scroll position, measured as the - * number of pixels off-screen to the left. */ - int maxLength; /* Length in pixels of longest line that's - * visible in window (length may exceed window - * size). If there's no wrapping, this will - * be zero. */ - double xScrollFirst, xScrollLast; - /* Most recent values reported to horizontal - * scrollbar; used to eliminate unnecessary - * reports. */ - double yScrollFirst, yScrollLast; - /* Most recent values reported to vertical - * scrollbar; used to eliminate unnecessary - * reports. */ - - /* - * The following information is used to implement scanning: - */ - - int scanMarkChar; /* Character that was at the left edge of - * the window when the scan started. */ - int scanMarkX; /* X-position of mouse at time scan started. */ - int scanTotalScroll; /* Total scrolling (in screen lines) that has - * occurred since scanMarkY was set. */ - int scanMarkY; /* Y-position of mouse at time scan started. */ - - /* - * Miscellaneous information: - */ - - int dLinesInvalidated; /* This value is set to 1 whenever something - * happens that invalidates information in - * DLine structures; if a redisplay - * is in progress, it will see this and - * abort the redisplay. This is needed - * because, for example, an embedded window - * could change its size when it is first - * displayed, invalidating the DLine that - * is currently being displayed. If redisplay - * continues, it will use freed memory and - * could dump core. */ - int flags; /* Various flag values: see below for - * definitions. */ -} TextDInfo; - -/* - * In TkTextDispChunk structures for character segments, the clientData - * field points to one of the following structures: - */ - -typedef struct CharInfo { - int numChars; /* Number of characters to display. */ - char chars[4]; /* Characters to display. Actual size - * will be numChars, not 4. THIS MUST BE - * THE LAST FIELD IN THE STRUCTURE. */ -} CharInfo; - -/* - * Flag values for TextDInfo structures: - * - * DINFO_OUT_OF_DATE: Non-zero means that the DLine structures - * for this window are partially or completely - * out of date and need to be recomputed. - * REDRAW_PENDING: Means that a when-idle handler has been - * scheduled to update the display. - * REDRAW_BORDERS: Means window border or pad area has - * potentially been damaged and must be redrawn. - * REPICK_NEEDED: 1 means that the widget has been modified - * in a way that could change the current - * character (a different character might be - * under the mouse cursor now). Need to - * recompute the current character before - * the next redisplay. - */ - -#define DINFO_OUT_OF_DATE 1 -#define REDRAW_PENDING 2 -#define REDRAW_BORDERS 4 -#define REPICK_NEEDED 8 - -/* - * The following counters keep statistics about redisplay that can be - * checked to see how clever this code is at reducing redisplays. - */ - -static int numRedisplays; /* Number of calls to DisplayText. */ -static int linesRedrawn; /* Number of calls to DisplayDLine. */ -static int numCopies; /* Number of calls to XCopyArea to copy part - * of the screen. */ - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void AdjustForTab _ANSI_ARGS_((TkText *textPtr, - TkTextTabArray *tabArrayPtr, int index, - TkTextDispChunk *chunkPtr)); -static void CharBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, - int index, int y, int lineHeight, int baseline, - int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -static void CharDisplayProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, - int x, int y, int height, int baseline, - Display *display, Drawable dst, int screenY)); -static int CharMeasureProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, - int x)); -static void CharUndisplayProc _ANSI_ARGS_((TkText *textPtr, - TkTextDispChunk *chunkPtr)); -static void DisplayDLine _ANSI_ARGS_((TkText *textPtr, - DLine *dlPtr, DLine *prevPtr, Pixmap pixmap)); -static void DisplayLineBackground _ANSI_ARGS_((TkText *textPtr, - DLine *dlPtr, DLine *prevPtr, Pixmap pixmap)); -static void DisplayText _ANSI_ARGS_((ClientData clientData)); -static DLine * FindDLine _ANSI_ARGS_((DLine *dlPtr, - TkTextIndex *indexPtr)); -static void FreeDLines _ANSI_ARGS_((TkText *textPtr, - DLine *firstPtr, DLine *lastPtr, int unlink)); -static void FreeStyle _ANSI_ARGS_((TkText *textPtr, - TextStyle *stylePtr)); -static TextStyle * GetStyle _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr)); -static void GetXView _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int report)); -static void GetYView _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int report)); -static DLine * LayoutDLine _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr)); -static int MeasureChars _ANSI_ARGS_((Tk_Font tkfont, - CONST char *source, int maxChars, int startX, - int maxX, int tabOrigin, int *nextXPtr)); -static void MeasureUp _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *srcPtr, int distance, - TkTextIndex *dstPtr)); -static int NextTabStop _ANSI_ARGS_((Tk_Font tkfont, int x, - int tabOrigin)); -static void UpdateDisplayInfo _ANSI_ARGS_((TkText *textPtr)); -static void ScrollByLines _ANSI_ARGS_((TkText *textPtr, - int offset)); -static int SizeOfTab _ANSI_ARGS_((TkText *textPtr, - TkTextTabArray *tabArrayPtr, int index, int x, - int maxX)); -static void TextInvalidateRegion _ANSI_ARGS_((TkText *textPtr, - TkRegion region)); - - -/* - *---------------------------------------------------------------------- - * - * TkTextCreateDInfo -- - * - * This procedure is called when a new text widget is created. - * Its job is to set up display-related information for the widget. - * - * Results: - * None. - * - * Side effects: - * A TextDInfo data structure is allocated and initialized and attached - * to textPtr. - * - *---------------------------------------------------------------------- - */ - -void -TkTextCreateDInfo(textPtr) - TkText *textPtr; /* Overall information for text widget. */ -{ - register TextDInfo *dInfoPtr; - XGCValues gcValues; - - dInfoPtr = (TextDInfo *) ckalloc(sizeof(TextDInfo)); - Tcl_InitHashTable(&dInfoPtr->styleTable, sizeof(StyleValues)/sizeof(int)); - dInfoPtr->dLinePtr = NULL; - dInfoPtr->copyGC = None; - gcValues.graphics_exposures = True; - dInfoPtr->scrollGC = Tk_GetGC(textPtr->tkwin, GCGraphicsExposures, - &gcValues); - dInfoPtr->topOfEof = 0; - dInfoPtr->newCharOffset = 0; - dInfoPtr->curPixelOffset = 0; - dInfoPtr->maxLength = 0; - dInfoPtr->xScrollFirst = -1; - dInfoPtr->xScrollLast = -1; - dInfoPtr->yScrollFirst = -1; - dInfoPtr->yScrollLast = -1; - dInfoPtr->scanMarkChar = 0; - dInfoPtr->scanMarkX = 0; - dInfoPtr->scanTotalScroll = 0; - dInfoPtr->scanMarkY = 0; - dInfoPtr->dLinesInvalidated = 0; - dInfoPtr->flags = DINFO_OUT_OF_DATE; - textPtr->dInfoPtr = dInfoPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextFreeDInfo -- - * - * This procedure is called to free up all of the private display - * information kept by this file for a text widget. - * - * Results: - * None. - * - * Side effects: - * Lots of resources get freed. - * - *---------------------------------------------------------------------- - */ - -void -TkTextFreeDInfo(textPtr) - TkText *textPtr; /* Overall information for text widget. */ -{ - register TextDInfo *dInfoPtr = textPtr->dInfoPtr; - - /* - * Be careful to free up styleTable *after* freeing up all the - * DLines, so that the hash table is still intact to free up the - * style-related information from the lines. Once the lines are - * all free then styleTable will be empty. - */ - - FreeDLines(textPtr, dInfoPtr->dLinePtr, (DLine *) NULL, 1); - Tcl_DeleteHashTable(&dInfoPtr->styleTable); - if (dInfoPtr->copyGC != None) { - Tk_FreeGC(textPtr->display, dInfoPtr->copyGC); - } - Tk_FreeGC(textPtr->display, dInfoPtr->scrollGC); - if (dInfoPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayText, (ClientData) textPtr); - } - ckfree((char *) dInfoPtr); -} - -/* - *---------------------------------------------------------------------- - * - * GetStyle -- - * - * This procedure creates all the information needed to display - * text at a particular location. - * - * Results: - * The return value is a pointer to a TextStyle structure that - * corresponds to *sValuePtr. - * - * Side effects: - * A new entry may be created in the style table for the widget. - * - *---------------------------------------------------------------------- - */ - -static TextStyle * -GetStyle(textPtr, indexPtr) - TkText *textPtr; /* Overall information about text widget. */ - TkTextIndex *indexPtr; /* The character in the text for which - * display information is wanted. */ -{ - TkTextTag **tagPtrs; - register TkTextTag *tagPtr; - StyleValues styleValues; - TextStyle *stylePtr; - Tcl_HashEntry *hPtr; - int numTags, new, i; - XGCValues gcValues; - unsigned long mask; - - /* - * The variables below keep track of the highest-priority specification - * that has occurred for each of the various fields of the StyleValues. - */ - - int borderPrio, borderWidthPrio, reliefPrio, bgStipplePrio; - int fgPrio, fontPrio, fgStipplePrio; - int underlinePrio, justifyPrio, offsetPrio; - int lMargin1Prio, lMargin2Prio, rMarginPrio; - int spacing1Prio, spacing2Prio, spacing3Prio; - int overstrikePrio, tabPrio, wrapPrio; - - /* - * Find out what tags are present for the character, then compute - * a StyleValues structure corresponding to those tags (scan - * through all of the tags, saving information for the highest- - * priority tag). - */ - - tagPtrs = TkBTreeGetTags(indexPtr, &numTags); - borderPrio = borderWidthPrio = reliefPrio = bgStipplePrio = -1; - fgPrio = fontPrio = fgStipplePrio = -1; - underlinePrio = justifyPrio = offsetPrio = -1; - lMargin1Prio = lMargin2Prio = rMarginPrio = -1; - spacing1Prio = spacing2Prio = spacing3Prio = -1; - overstrikePrio = tabPrio = wrapPrio = -1; - memset((VOID *) &styleValues, 0, sizeof(StyleValues)); - styleValues.relief = TK_RELIEF_FLAT; - styleValues.fgColor = textPtr->fgColor; - styleValues.tkfont = textPtr->tkfont; - styleValues.justify = TK_JUSTIFY_LEFT; - styleValues.spacing1 = textPtr->spacing1; - styleValues.spacing2 = textPtr->spacing2; - styleValues.spacing3 = textPtr->spacing3; - styleValues.tabArrayPtr = textPtr->tabArrayPtr; - styleValues.wrapMode = textPtr->wrapMode; - for (i = 0 ; i < numTags; i++) { - tagPtr = tagPtrs[i]; - - /* - * On Windows and Mac, we need to skip the selection tag if - * we don't have focus. - */ - -#ifndef ALWAYS_SHOW_SELECTION - if ((tagPtr == textPtr->selTagPtr) && !(textPtr->flags & GOT_FOCUS)) { - continue; - } -#endif - - if ((tagPtr->border != NULL) && (tagPtr->priority > borderPrio)) { - styleValues.border = tagPtr->border; - borderPrio = tagPtr->priority; - } - if ((tagPtr->bdString != NULL) - && (tagPtr->priority > borderWidthPrio)) { - styleValues.borderWidth = tagPtr->borderWidth; - borderWidthPrio = tagPtr->priority; - } - if ((tagPtr->reliefString != NULL) - && (tagPtr->priority > reliefPrio)) { - if (styleValues.border == NULL) { - styleValues.border = textPtr->border; - } - styleValues.relief = tagPtr->relief; - reliefPrio = tagPtr->priority; - } - if ((tagPtr->bgStipple != None) - && (tagPtr->priority > bgStipplePrio)) { - styleValues.bgStipple = tagPtr->bgStipple; - bgStipplePrio = tagPtr->priority; - } - if ((tagPtr->fgColor != None) && (tagPtr->priority > fgPrio)) { - styleValues.fgColor = tagPtr->fgColor; - fgPrio = tagPtr->priority; - } - if ((tagPtr->tkfont != None) && (tagPtr->priority > fontPrio)) { - styleValues.tkfont = tagPtr->tkfont; - fontPrio = tagPtr->priority; - } - if ((tagPtr->fgStipple != None) - && (tagPtr->priority > fgStipplePrio)) { - styleValues.fgStipple = tagPtr->fgStipple; - fgStipplePrio = tagPtr->priority; - } - if ((tagPtr->justifyString != NULL) - && (tagPtr->priority > justifyPrio)) { - styleValues.justify = tagPtr->justify; - justifyPrio = tagPtr->priority; - } - if ((tagPtr->lMargin1String != NULL) - && (tagPtr->priority > lMargin1Prio)) { - styleValues.lMargin1 = tagPtr->lMargin1; - lMargin1Prio = tagPtr->priority; - } - if ((tagPtr->lMargin2String != NULL) - && (tagPtr->priority > lMargin2Prio)) { - styleValues.lMargin2 = tagPtr->lMargin2; - lMargin2Prio = tagPtr->priority; - } - if ((tagPtr->offsetString != NULL) - && (tagPtr->priority > offsetPrio)) { - styleValues.offset = tagPtr->offset; - offsetPrio = tagPtr->priority; - } - if ((tagPtr->overstrikeString != NULL) - && (tagPtr->priority > overstrikePrio)) { - styleValues.overstrike = tagPtr->overstrike; - overstrikePrio = tagPtr->priority; - } - if ((tagPtr->rMarginString != NULL) - && (tagPtr->priority > rMarginPrio)) { - styleValues.rMargin = tagPtr->rMargin; - rMarginPrio = tagPtr->priority; - } - if ((tagPtr->spacing1String != NULL) - && (tagPtr->priority > spacing1Prio)) { - styleValues.spacing1 = tagPtr->spacing1; - spacing1Prio = tagPtr->priority; - } - if ((tagPtr->spacing2String != NULL) - && (tagPtr->priority > spacing2Prio)) { - styleValues.spacing2 = tagPtr->spacing2; - spacing2Prio = tagPtr->priority; - } - if ((tagPtr->spacing3String != NULL) - && (tagPtr->priority > spacing3Prio)) { - styleValues.spacing3 = tagPtr->spacing3; - spacing3Prio = tagPtr->priority; - } - if ((tagPtr->tabString != NULL) - && (tagPtr->priority > tabPrio)) { - styleValues.tabArrayPtr = tagPtr->tabArrayPtr; - tabPrio = tagPtr->priority; - } - if ((tagPtr->underlineString != NULL) - && (tagPtr->priority > underlinePrio)) { - styleValues.underline = tagPtr->underline; - underlinePrio = tagPtr->priority; - } - if ((tagPtr->wrapMode != NULL) - && (tagPtr->priority > wrapPrio)) { - styleValues.wrapMode = tagPtr->wrapMode; - wrapPrio = tagPtr->priority; - } - } - if (tagPtrs != NULL) { - ckfree((char *) tagPtrs); - } - - /* - * Use an existing style if there's one around that matches. - */ - - hPtr = Tcl_CreateHashEntry(&textPtr->dInfoPtr->styleTable, - (char *) &styleValues, &new); - if (!new) { - stylePtr = (TextStyle *) Tcl_GetHashValue(hPtr); - stylePtr->refCount++; - return stylePtr; - } - - /* - * No existing style matched. Make a new one. - */ - - stylePtr = (TextStyle *) ckalloc(sizeof(TextStyle)); - stylePtr->refCount = 1; - if (styleValues.border != NULL) { - gcValues.foreground = Tk_3DBorderColor(styleValues.border)->pixel; - mask = GCForeground; - if (styleValues.bgStipple != None) { - gcValues.stipple = styleValues.bgStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - stylePtr->bgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); - } else { - stylePtr->bgGC = None; - } - mask = GCForeground|GCFont; - gcValues.foreground = styleValues.fgColor->pixel; - gcValues.font = Tk_FontId(styleValues.tkfont); - if (styleValues.fgStipple != None) { - gcValues.stipple = styleValues.fgStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); - stylePtr->sValuePtr = (StyleValues *) - Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr); - stylePtr->hPtr = hPtr; - Tcl_SetHashValue(hPtr, stylePtr); - return stylePtr; -} - -/* - *---------------------------------------------------------------------- - * - * FreeStyle -- - * - * This procedure is called when a TextStyle structure is no longer - * needed. It decrements the reference count and frees up the - * space for the style structure if the reference count is 0. - * - * Results: - * None. - * - * Side effects: - * The storage and other resources associated with the style - * are freed up if no-one's still using it. - * - *---------------------------------------------------------------------- - */ - -static void -FreeStyle(textPtr, stylePtr) - TkText *textPtr; /* Information about overall widget. */ - register TextStyle *stylePtr; /* Information about style to free. */ - -{ - stylePtr->refCount--; - if (stylePtr->refCount == 0) { - if (stylePtr->bgGC != None) { - Tk_FreeGC(textPtr->display, stylePtr->bgGC); - } - Tk_FreeGC(textPtr->display, stylePtr->fgGC); - Tcl_DeleteHashEntry(stylePtr->hPtr); - ckfree((char *) stylePtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * LayoutDLine -- - * - * This procedure generates a single DLine structure for a display - * line whose leftmost character is given by indexPtr. - * - * Results: - * The return value is a pointer to a DLine structure desribing the - * display line. All fields are filled in and correct except for - * y and nextPtr. - * - * Side effects: - * Storage is allocated for the new DLine. - * - *---------------------------------------------------------------------- - */ - -static DLine * -LayoutDLine(textPtr, indexPtr) - TkText *textPtr; /* Overall information about text widget. */ - TkTextIndex *indexPtr; /* Beginning of display line. May not - * necessarily point to a character segment. */ -{ - register DLine *dlPtr; /* New display line. */ - TkTextSegment *segPtr; /* Current segment in text. */ - TkTextDispChunk *lastChunkPtr; /* Last chunk allocated so far - * for line. */ - TkTextDispChunk *chunkPtr; /* Current chunk. */ - TkTextIndex curIndex; - TkTextDispChunk *breakChunkPtr; /* Chunk containing best word break - * point, if any. */ - TkTextIndex breakIndex; /* Index of first character in - * breakChunkPtr. */ - int breakCharOffset; /* Character within breakChunkPtr just - * to right of best break point. */ - int noCharsYet; /* Non-zero means that no characters - * have been placed on the line yet. */ - int justify; /* How to justify line: taken from - * style for first character in line. */ - int jIndent; /* Additional indentation (beyond - * margins) due to justification. */ - int rMargin; /* Right margin width for line. */ - Tk_Uid wrapMode; /* Wrap mode to use for this line. */ - int x = 0, maxX = 0; /* Initializations needed only to - * stop compiler warnings. */ - int wholeLine; /* Non-zero means this display line - * runs to the end of the text line. */ - int tabIndex; /* Index of the current tab stop. */ - int gotTab; /* Non-zero means the current chunk - * contains a tab. */ - TkTextDispChunk *tabChunkPtr; /* Pointer to the chunk containing - * the previous tab stop. */ - int maxChars; /* Maximum number of characters to - * include in this chunk. */ - TkTextTabArray *tabArrayPtr; /* Tab stops for line; taken from - * style for first character on line. */ - int tabSize; /* Number of pixels consumed by current - * tab stop. */ - TkTextDispChunk *lastCharChunkPtr; /* Pointer to last chunk in display - * lines with numChars > 0. Used to - * drop 0-sized chunks from the end - * of the line. */ - int offset, ascent, descent, code; - StyleValues *sValuePtr; - - /* - * Create and initialize a new DLine structure. - */ - - dlPtr = (DLine *) ckalloc(sizeof(DLine)); - dlPtr->index = *indexPtr; - dlPtr->count = 0; - dlPtr->y = 0; - dlPtr->oldY = -1; - dlPtr->height = 0; - dlPtr->baseline = 0; - dlPtr->chunkPtr = NULL; - dlPtr->nextPtr = NULL; - dlPtr->flags = NEW_LAYOUT; - - /* - * Each iteration of the loop below creates one TkTextDispChunk for - * the new display line. The line will always have at least one - * chunk (for the newline character at the end, if there's nothing - * else available). - */ - - curIndex = *indexPtr; - lastChunkPtr = NULL; - chunkPtr = NULL; - noCharsYet = 1; - breakChunkPtr = NULL; - breakCharOffset = 0; - justify = TK_JUSTIFY_LEFT; - tabIndex = -1; - tabChunkPtr = NULL; - tabArrayPtr = NULL; - rMargin = 0; - wrapMode = tkTextCharUid; - tabSize = 0; - lastCharChunkPtr = NULL; - - /* - * Find the first segment to consider for the line. Can't call - * TkTextIndexToSeg for this because it won't return a segment - * with zero size (such as the insertion cursor's mark). - */ - - for (offset = curIndex.charIndex, segPtr = curIndex.linePtr->segPtr; - (offset > 0) && (offset >= segPtr->size); - offset -= segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body. */ - } - - while (segPtr != NULL) { - if (segPtr->typePtr->layoutProc == NULL) { - segPtr = segPtr->nextPtr; - offset = 0; - continue; - } - if (chunkPtr == NULL) { - chunkPtr = (TkTextDispChunk *) ckalloc(sizeof(TkTextDispChunk)); - chunkPtr->nextPtr = NULL; - } - chunkPtr->stylePtr = GetStyle(textPtr, &curIndex); - - /* - * Save style information such as justification and indentation, - * up until the first character is encountered, then retain that - * information for the rest of the line. - */ - - if (noCharsYet) { - tabArrayPtr = chunkPtr->stylePtr->sValuePtr->tabArrayPtr; - justify = chunkPtr->stylePtr->sValuePtr->justify; - rMargin = chunkPtr->stylePtr->sValuePtr->rMargin; - wrapMode = chunkPtr->stylePtr->sValuePtr->wrapMode; - x = ((curIndex.charIndex == 0) - ? chunkPtr->stylePtr->sValuePtr->lMargin1 - : chunkPtr->stylePtr->sValuePtr->lMargin2); - if (wrapMode == tkTextNoneUid) { - maxX = INT_MAX; - } else { - maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - - rMargin; - if (maxX < x) { - maxX = x; - } - } - } - - /* - * See if there is a tab in the current chunk; if so, only - * layout characters up to (and including) the tab. - */ - - gotTab = 0; - maxChars = segPtr->size - offset; - if (justify == TK_JUSTIFY_LEFT) { - if (segPtr->typePtr == &tkTextCharType) { - char *p; - - for (p = segPtr->body.chars + offset; *p != 0; p++) { - if (*p == '\t') { - maxChars = (p + 1 - segPtr->body.chars) - offset; - gotTab = 1; - break; - } - } - } - } - - chunkPtr->x = x; - code = (*segPtr->typePtr->layoutProc)(textPtr, &curIndex, segPtr, - offset, maxX-tabSize, maxChars, noCharsYet, wrapMode, - chunkPtr); - if (code <= 0) { - FreeStyle(textPtr, chunkPtr->stylePtr); - if (code < 0) { - /* - * This segment doesn't wish to display itself (e.g. most - * marks). - */ - - segPtr = segPtr->nextPtr; - offset = 0; - continue; - } - - /* - * No characters from this segment fit in the window: this - * means we're at the end of the display line. - */ - - if (chunkPtr != NULL) { - ckfree((char *) chunkPtr); - } - break; - } - if (chunkPtr->numChars > 0) { - noCharsYet = 0; - lastCharChunkPtr = chunkPtr; - } - if (lastChunkPtr == NULL) { - dlPtr->chunkPtr = chunkPtr; - } else { - lastChunkPtr->nextPtr = chunkPtr; - } - lastChunkPtr = chunkPtr; - x += chunkPtr->width; - if (chunkPtr->breakIndex > 0) { - breakCharOffset = chunkPtr->breakIndex; - breakIndex = curIndex; - breakChunkPtr = chunkPtr; - } - if (chunkPtr->numChars != maxChars) { - break; - } - - /* - * If we're at a new tab, adjust the layout for all the chunks - * pertaining to the previous tab. Also adjust the amount of - * space left in the line to account for space that will be eaten - * up by the tab. - */ - - if (gotTab) { - if (tabIndex >= 0) { - AdjustForTab(textPtr, tabArrayPtr, tabIndex, tabChunkPtr); - x = chunkPtr->x + chunkPtr->width; - } - tabIndex++; - tabChunkPtr = chunkPtr; - tabSize = SizeOfTab(textPtr, tabArrayPtr, tabIndex, x, maxX); - if (tabSize >= (maxX - x)) { - break; - } - } - curIndex.charIndex += chunkPtr->numChars; - offset += chunkPtr->numChars; - if (offset >= segPtr->size) { - offset = 0; - segPtr = segPtr->nextPtr; - } - chunkPtr = NULL; - } - if (noCharsYet) { - panic("LayoutDLine couldn't place any characters on a line"); - } - wholeLine = (segPtr == NULL); - - /* - * We're at the end of the display line. Throw away everything - * after the most recent word break, if there is one; this may - * potentially require the last chunk to be layed out again. - */ - - if (breakChunkPtr == NULL) { - /* - * This code makes sure that we don't accidentally display - * chunks with no characters at the end of the line (such as - * the insertion cursor). These chunks belong on the next - * line. So, throw away everything after the last chunk that - * has characters in it. - */ - - breakChunkPtr = lastCharChunkPtr; - breakCharOffset = breakChunkPtr->numChars; - } - if ((breakChunkPtr != NULL) && ((lastChunkPtr != breakChunkPtr) - || (breakCharOffset != lastChunkPtr->numChars))) { - while (1) { - chunkPtr = breakChunkPtr->nextPtr; - if (chunkPtr == NULL) { - break; - } - FreeStyle(textPtr, chunkPtr->stylePtr); - breakChunkPtr->nextPtr = chunkPtr->nextPtr; - (*chunkPtr->undisplayProc)(textPtr, chunkPtr); - ckfree((char *) chunkPtr); - } - if (breakCharOffset != breakChunkPtr->numChars) { - (*breakChunkPtr->undisplayProc)(textPtr, breakChunkPtr); - segPtr = TkTextIndexToSeg(&breakIndex, &offset); - (*segPtr->typePtr->layoutProc)(textPtr, &breakIndex, - segPtr, offset, maxX, breakCharOffset, 0, - wrapMode, breakChunkPtr); - } - lastChunkPtr = breakChunkPtr; - wholeLine = 0; - } - - /* - * Make tab adjustments for the last tab stop, if there is one. - */ - - if ((tabIndex >= 0) && (tabChunkPtr != NULL)) { - AdjustForTab(textPtr, tabArrayPtr, tabIndex, tabChunkPtr); - } - - /* - * Make one more pass over the line to recompute various things - * like its height, length, and total number of characters. Also - * modify the x-locations of chunks to reflect justification. - * If we're not wrapping, I'm not sure what is the best way to - * handle left and center justification: should the total length, - * for purposes of justification, be (a) the window width, (b) - * the length of the longest line in the window, or (c) the length - * of the longest line in the text? (c) isn't available, (b) seems - * weird, since it can change with vertical scrolling, so (a) is - * what is implemented below. - */ - - if (wrapMode == tkTextNoneUid) { - maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - rMargin; - } - dlPtr->length = lastChunkPtr->x + lastChunkPtr->width; - if (justify == TK_JUSTIFY_LEFT) { - jIndent = 0; - } else if (justify == TK_JUSTIFY_RIGHT) { - jIndent = maxX - dlPtr->length; - } else { - jIndent = (maxX - dlPtr->length)/2; - } - ascent = descent = 0; - for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL; - chunkPtr = chunkPtr->nextPtr) { - chunkPtr->x += jIndent; - dlPtr->count += chunkPtr->numChars; - if (chunkPtr->minAscent > ascent) { - ascent = chunkPtr->minAscent; - } - if (chunkPtr->minDescent > descent) { - descent = chunkPtr->minDescent; - } - if (chunkPtr->minHeight > dlPtr->height) { - dlPtr->height = chunkPtr->minHeight; - } - sValuePtr = chunkPtr->stylePtr->sValuePtr; - if ((sValuePtr->borderWidth > 0) - && (sValuePtr->relief != TK_RELIEF_FLAT)) { - dlPtr->flags |= HAS_3D_BORDER; - } - } - if (dlPtr->height < (ascent + descent)) { - dlPtr->height = ascent + descent; - dlPtr->baseline = ascent; - } else { - dlPtr->baseline = ascent + (dlPtr->height - ascent - descent)/2; - } - sValuePtr = dlPtr->chunkPtr->stylePtr->sValuePtr; - if (dlPtr->index.charIndex == 0) { - dlPtr->spaceAbove = sValuePtr->spacing1; - } else { - dlPtr->spaceAbove = sValuePtr->spacing2 - sValuePtr->spacing2/2; - } - if (wholeLine) { - dlPtr->spaceBelow = sValuePtr->spacing3; - } else { - dlPtr->spaceBelow = sValuePtr->spacing2/2; - } - dlPtr->height += dlPtr->spaceAbove + dlPtr->spaceBelow; - dlPtr->baseline += dlPtr->spaceAbove; - - /* - * Recompute line length: may have changed because of justification. - */ - - dlPtr->length = lastChunkPtr->x + lastChunkPtr->width; - return dlPtr; -} - -/* - *---------------------------------------------------------------------- - * - * UpdateDisplayInfo -- - * - * This procedure is invoked to recompute some or all of the - * DLine structures for a text widget. At the time it is called - * the DLine structures still left in the widget are guaranteed - * to be correct except that (a) the y-coordinates aren't - * necessarily correct, (b) there may be missing structures - * (the DLine structures get removed as soon as they are potentially - * out-of-date), and (c) DLine structures that don't start at the - * beginning of a line may be incorrect if previous information in - * the same line changed size in a way that moved a line boundary - * (DLines for any info that changed will have been deleted, but - * not DLines for unchanged info in the same text line). - * - * Results: - * None. - * - * Side effects: - * Upon return, the DLine information for textPtr correctly reflects - * the positions where characters will be displayed. However, this - * procedure doesn't actually bring the display up-to-date. - * - *---------------------------------------------------------------------- - */ - -static void -UpdateDisplayInfo(textPtr) - TkText *textPtr; /* Text widget to update. */ -{ - register TextDInfo *dInfoPtr = textPtr->dInfoPtr; - register DLine *dlPtr, *prevPtr; - TkTextIndex index; - TkTextLine *lastLinePtr; - int y, maxY, pixelOffset, maxOffset; - - if (!(dInfoPtr->flags & DINFO_OUT_OF_DATE)) { - return; - } - dInfoPtr->flags &= ~DINFO_OUT_OF_DATE; - - /* - * Delete any DLines that are now above the top of the window. - */ - - index = textPtr->topIndex; - dlPtr = FindDLine(dInfoPtr->dLinePtr, &index); - if ((dlPtr != NULL) && (dlPtr != dInfoPtr->dLinePtr)) { - FreeDLines(textPtr, dInfoPtr->dLinePtr, dlPtr, 1); - } - - /* - *-------------------------------------------------------------- - * Scan through the contents of the window from top to bottom, - * recomputing information for lines that are missing. - *-------------------------------------------------------------- - */ - - lastLinePtr = TkBTreeFindLine(textPtr->tree, - TkBTreeNumLines(textPtr->tree)); - dlPtr = dInfoPtr->dLinePtr; - prevPtr = NULL; - y = dInfoPtr->y; - maxY = dInfoPtr->maxY; - while (1) { - register DLine *newPtr; - - if (index.linePtr == lastLinePtr) { - break; - } - - /* - * There are three possibilities right now: - * (a) the next DLine (dlPtr) corresponds exactly to the next - * information we want to display: just use it as-is. - * (b) the next DLine corresponds to a different line, or to - * a segment that will be coming later in the same line: - * leave this DLine alone in the hopes that we'll be able - * to use it later, then create a new DLine in front of - * it. - * (c) the next DLine corresponds to a segment in the line we - * want, but it's a segment that has already been processed - * or will never be processed. Delete the DLine and try - * again. - * - * One other twist on all this. It's possible for 3D borders - * to interact between lines (see DisplayLineBackground) so if - * a line is relayed out and has styles with 3D borders, its - * neighbors have to be redrawn if they have 3D borders too, - * since the interactions could have changed (the neighbors - * don't have to be relayed out, just redrawn). - */ - - if ((dlPtr == NULL) || (dlPtr->index.linePtr != index.linePtr)) { - /* - * Case (b) -- must make new DLine. - */ - - makeNewDLine: - if (tkTextDebug) { - char string[TK_POS_CHARS]; - - /* - * Debugging is enabled, so keep a log of all the lines - * that were re-layed out. The test suite uses this - * information. - */ - - TkTextPrintIndex(&index, string); - Tcl_SetVar2(textPtr->interp, "tk_textRelayout", (char *) NULL, - string, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - } - newPtr = LayoutDLine(textPtr, &index); - if (prevPtr == NULL) { - dInfoPtr->dLinePtr = newPtr; - } else { - prevPtr->nextPtr = newPtr; - if (prevPtr->flags & HAS_3D_BORDER) { - prevPtr->oldY = -1; - } - } - newPtr->nextPtr = dlPtr; - dlPtr = newPtr; - } else { - /* - * DlPtr refers to the line we want. Next check the - * index within the line. - */ - - if (index.charIndex == dlPtr->index.charIndex) { - /* - * Case (a) -- can use existing display line as-is. - */ - - if ((dlPtr->flags & HAS_3D_BORDER) && (prevPtr != NULL) - && (prevPtr->flags & (NEW_LAYOUT))) { - dlPtr->oldY = -1; - } - goto lineOK; - } - if (index.charIndex < dlPtr->index.charIndex) { - goto makeNewDLine; - } - - /* - * Case (c) -- dlPtr is useless. Discard it and start - * again with the next display line. - */ - - newPtr = dlPtr->nextPtr; - FreeDLines(textPtr, dlPtr, newPtr, 0); - dlPtr = newPtr; - if (prevPtr != NULL) { - prevPtr->nextPtr = newPtr; - } else { - dInfoPtr->dLinePtr = newPtr; - } - continue; - } - - /* - * Advance to the start of the next line. - */ - - lineOK: - dlPtr->y = y; - y += dlPtr->height; - TkTextIndexForwChars(&index, dlPtr->count, &index); - prevPtr = dlPtr; - dlPtr = dlPtr->nextPtr; - - /* - * If we switched text lines, delete any DLines left for the - * old text line. - */ - - if (index.linePtr != prevPtr->index.linePtr) { - register DLine *nextPtr; - - nextPtr = dlPtr; - while ((nextPtr != NULL) - && (nextPtr->index.linePtr == prevPtr->index.linePtr)) { - nextPtr = nextPtr->nextPtr; - } - if (nextPtr != dlPtr) { - FreeDLines(textPtr, dlPtr, nextPtr, 0); - prevPtr->nextPtr = nextPtr; - dlPtr = nextPtr; - } - } - - /* - * It's important to have the following check here rather than in - * the while statement for the loop, so that there's always at least - * one DLine generated, regardless of how small the window is. This - * keeps a lot of other code from breaking. - */ - - if (y >= maxY) { - break; - } - } - - /* - * Delete any DLine structures that don't fit on the screen. - */ - - FreeDLines(textPtr, dlPtr, (DLine *) NULL, 1); - - /* - *-------------------------------------------------------------- - * If there is extra space at the bottom of the window (because - * we've hit the end of the text), then bring in more lines at - * the top of the window, if there are any, to fill in the view. - *-------------------------------------------------------------- - */ - - if (y < maxY) { - int lineNum, spaceLeft, charsToCount; - DLine *lowestPtr; - - /* - * Layout an entire text line (potentially > 1 display line), - * then link in as many display lines as fit without moving - * the bottom line out of the window. Repeat this until - * all the extra space has been used up or we've reached the - * beginning of the text. - */ - - spaceLeft = maxY - y; - lineNum = TkBTreeLineIndex(dInfoPtr->dLinePtr->index.linePtr); - charsToCount = dInfoPtr->dLinePtr->index.charIndex; - if (charsToCount == 0) { - charsToCount = INT_MAX; - lineNum--; - } - for ( ; (lineNum >= 0) && (spaceLeft > 0); lineNum--) { - index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); - index.charIndex = 0; - lowestPtr = NULL; - do { - dlPtr = LayoutDLine(textPtr, &index); - dlPtr->nextPtr = lowestPtr; - lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) - && (index.linePtr == lowestPtr->index.linePtr)); - - /* - * Scan through the display lines from the bottom one up to - * the top one. - */ - - while (lowestPtr != NULL) { - dlPtr = lowestPtr; - spaceLeft -= dlPtr->height; - if (spaceLeft < 0) { - break; - } - lowestPtr = dlPtr->nextPtr; - dlPtr->nextPtr = dInfoPtr->dLinePtr; - dInfoPtr->dLinePtr = dlPtr; - if (tkTextDebug) { - char string[TK_POS_CHARS]; - - TkTextPrintIndex(&dlPtr->index, string); - Tcl_SetVar2(textPtr->interp, "tk_textRelayout", - (char *) NULL, string, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - } - } - FreeDLines(textPtr, lowestPtr, (DLine *) NULL, 0); - charsToCount = INT_MAX; - } - - /* - * Now we're all done except that the y-coordinates in all the - * DLines are wrong and the top index for the text is wrong. - * Update them. - */ - - textPtr->topIndex = dInfoPtr->dLinePtr->index; - y = dInfoPtr->y; - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; - dlPtr = dlPtr->nextPtr) { - if (y > dInfoPtr->maxY) { - panic("Added too many new lines in UpdateDisplayInfo"); - } - dlPtr->y = y; - y += dlPtr->height; - } - } - - /* - *-------------------------------------------------------------- - * If the old top or bottom line has scrolled elsewhere on the - * screen, we may not be able to re-use its old contents by - * copying bits (e.g., a beveled edge that was drawn when it was - * at the top or bottom won't be drawn when the line is in the - * middle and its neighbor has a matching background). Similarly, - * if the new top or bottom line came from somewhere else on the - * screen, we may not be able to copy the old bits. - *-------------------------------------------------------------- - */ - - dlPtr = dInfoPtr->dLinePtr; - if ((dlPtr->flags & HAS_3D_BORDER) && !(dlPtr->flags & TOP_LINE)) { - dlPtr->oldY = -1; - } - while (1) { - if ((dlPtr->flags & TOP_LINE) && (dlPtr != dInfoPtr->dLinePtr) - && (dlPtr->flags & HAS_3D_BORDER)) { - dlPtr->oldY = -1; - } - if ((dlPtr->flags & BOTTOM_LINE) && (dlPtr->nextPtr != NULL) - && (dlPtr->flags & HAS_3D_BORDER)) { - dlPtr->oldY = -1; - } - if (dlPtr->nextPtr == NULL) { - if ((dlPtr->flags & HAS_3D_BORDER) - && !(dlPtr->flags & BOTTOM_LINE)) { - dlPtr->oldY = -1; - } - dlPtr->flags &= ~TOP_LINE; - dlPtr->flags |= BOTTOM_LINE; - break; - } - dlPtr->flags &= ~(TOP_LINE|BOTTOM_LINE); - dlPtr = dlPtr->nextPtr; - } - dInfoPtr->dLinePtr->flags |= TOP_LINE; - - /* - * Arrange for scrollbars to be updated. - */ - - textPtr->flags |= UPDATE_SCROLLBARS; - - /* - *-------------------------------------------------------------- - * Deal with horizontal scrolling: - * 1. If there's empty space to the right of the longest line, - * shift the screen to the right to fill in the empty space. - * 2. If the desired horizontal scroll position has changed, - * force a full redisplay of all the lines in the widget. - * 3. If the wrap mode isn't "none" then re-scroll to the base - * position. - *-------------------------------------------------------------- - */ - - dInfoPtr->maxLength = 0; - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; - dlPtr = dlPtr->nextPtr) { - if (dlPtr->length > dInfoPtr->maxLength) { - dInfoPtr->maxLength = dlPtr->length; - } - } - maxOffset = (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) - + textPtr->charWidth - 1)/textPtr->charWidth; - if (dInfoPtr->newCharOffset > maxOffset) { - dInfoPtr->newCharOffset = maxOffset; - } - if (dInfoPtr->newCharOffset < 0) { - dInfoPtr->newCharOffset = 0; - } - pixelOffset = dInfoPtr->newCharOffset * textPtr->charWidth; - if (pixelOffset != dInfoPtr->curPixelOffset) { - dInfoPtr->curPixelOffset = pixelOffset; - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; - dlPtr = dlPtr->nextPtr) { - dlPtr->oldY = -1; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * FreeDLines -- - * - * This procedure is called to free up all of the resources - * associated with one or more DLine structures. - * - * Results: - * None. - * - * Side effects: - * Memory gets freed and various other resources are released. - * - *---------------------------------------------------------------------- - */ - -static void -FreeDLines(textPtr, firstPtr, lastPtr, unlink) - TkText *textPtr; /* Information about overall text - * widget. */ - register DLine *firstPtr; /* Pointer to first DLine to free up. */ - DLine *lastPtr; /* Pointer to DLine just after last - * one to free (NULL means everything - * starting with firstPtr). */ - int unlink; /* 1 means DLines are currently linked - * into the list rooted at - * textPtr->dInfoPtr->dLinePtr and - * they have to be unlinked. 0 means - * just free without unlinking. */ -{ - register TkTextDispChunk *chunkPtr, *nextChunkPtr; - register DLine *nextDLinePtr; - - if (unlink) { - if (textPtr->dInfoPtr->dLinePtr == firstPtr) { - textPtr->dInfoPtr->dLinePtr = lastPtr; - } else { - register DLine *prevPtr; - for (prevPtr = textPtr->dInfoPtr->dLinePtr; - prevPtr->nextPtr != firstPtr; prevPtr = prevPtr->nextPtr) { - /* Empty loop body. */ - } - prevPtr->nextPtr = lastPtr; - } - } - while (firstPtr != lastPtr) { - nextDLinePtr = firstPtr->nextPtr; - for (chunkPtr = firstPtr->chunkPtr; chunkPtr != NULL; - chunkPtr = nextChunkPtr) { - if (chunkPtr->undisplayProc != NULL) { - (*chunkPtr->undisplayProc)(textPtr, chunkPtr); - } - FreeStyle(textPtr, chunkPtr->stylePtr); - nextChunkPtr = chunkPtr->nextPtr; - ckfree((char *) chunkPtr); - } - ckfree((char *) firstPtr); - firstPtr = nextDLinePtr; - } - textPtr->dInfoPtr->dLinesInvalidated = 1; -} - -/* - *---------------------------------------------------------------------- - * - * DisplayDLine -- - * - * This procedure is invoked to draw a single line on the - * screen. - * - * Results: - * None. - * - * Side effects: - * The line given by dlPtr is drawn at its correct position in - * textPtr's window. Note that this is one *display* line, not - * one *text* line. - * - *---------------------------------------------------------------------- - */ - -static void -DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) - TkText *textPtr; /* Text widget in which to draw line. */ - register DLine *dlPtr; /* Information about line to draw. */ - DLine *prevPtr; /* Line just before one to draw, or NULL - * if dlPtr is the top line. */ - Pixmap pixmap; /* Pixmap to use for double-buffering. - * Caller must make sure it's large enough - * to hold line. */ -{ - register TkTextDispChunk *chunkPtr; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - Display *display; - int height, x; - - /* - * First, clear the area of the line to the background color for the - * text widget. - */ - - display = Tk_Display(textPtr->tkwin); - Tk_Fill3DRectangle(textPtr->tkwin, pixmap, textPtr->border, 0, 0, - Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT); - - /* - * Next, draw background information for the whole line. - */ - - DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap); - - /* - * Make another pass through all of the chunks to redraw the - * insertion cursor, if it is visible on this line. Must do - * it here rather than in the foreground pass below because - * otherwise a wide insertion cursor will obscure the character - * to its left. - */ - - if (textPtr->state == tkNormalUid) { - for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); - chunkPtr = chunkPtr->nextPtr) { - x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; - if (chunkPtr->displayProc == TkTextInsertDisplayProc) { - (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->spaceAbove, - dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, - dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, - dlPtr->y + dlPtr->spaceAbove); - } - } - } - - /* - * Make yet another pass through all of the chunks to redraw all of - * foreground information. Note: we have to call the displayProc - * even for chunks that are off-screen. This is needed, for - * example, so that embedded windows can be unmapped in this case. - * Conve - */ - - for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); - chunkPtr = chunkPtr->nextPtr) { - if (chunkPtr->displayProc == TkTextInsertDisplayProc) { - /* - * Already displayed the insertion cursor above. Don't - * do it again here. - */ - - continue; - } - x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; - if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) { - /* - * Note: we have to call the displayProc even for chunks - * that are off-screen. This is needed, for example, so - * that embedded windows can be unmapped in this case. - * Display the chunk at a coordinate that can be clearly - * identified by the displayProc as being off-screen to - * the left (the displayProc may not be able to tell if - * something is off to the right). - */ - - (*chunkPtr->displayProc)(chunkPtr, -chunkPtr->width, - dlPtr->spaceAbove, - dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, - dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, - dlPtr->y + dlPtr->spaceAbove); - } else { - (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->spaceAbove, - dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, - dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, - dlPtr->y + dlPtr->spaceAbove); - } - if (dInfoPtr->dLinesInvalidated) { - return; - } - } - - /* - * Copy the pixmap onto the screen. If this is the last line on - * the screen then copy a piece of the line, so that it doesn't - * overflow into the border area. Another special trick: copy the - * padding area to the left of the line; this is because the - * insertion cursor sometimes overflows onto that area and we want - * to get as much of the cursor as possible. - */ - - height = dlPtr->height; - if ((height + dlPtr->y) > dInfoPtr->maxY) { - height = dInfoPtr->maxY - dlPtr->y; - } - XCopyArea(display, pixmap, Tk_WindowId(textPtr->tkwin), dInfoPtr->copyGC, - dInfoPtr->x, 0, (unsigned) (dInfoPtr->maxX - dInfoPtr->x), - (unsigned) height, dInfoPtr->x, dlPtr->y); - linesRedrawn++; -} - -/* - *-------------------------------------------------------------- - * - * DisplayLineBackground -- - * - * This procedure is called to fill in the background for - * a display line. It draws 3D borders cleverly so that - * adjacent chunks with the same style (whether on the same - * line or different lines) have a single 3D border around - * the whole region. - * - * Results: - * There is no return value. Pixmap is filled in with background - * information for dlPtr. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) - TkText *textPtr; /* Text widget containing line. */ - register DLine *dlPtr; /* Information about line to draw. */ - DLine *prevPtr; /* Line just above dlPtr, or NULL if dlPtr - * is the top-most line in the window. */ - Pixmap pixmap; /* Pixmap to use for double-buffering. - * Caller must make sure it's large enough - * to hold line. Caller must also have - * filled it with the background color for - * the widget. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkTextDispChunk *chunkPtr; /* Pointer to chunk in the current line. */ - TkTextDispChunk *chunkPtr2; /* Pointer to chunk in the line above or - * below the current one. NULL if we're to - * the left of or to the right of the chunks - * in the line. */ - TkTextDispChunk *nextPtr2; /* Next chunk after chunkPtr2 (it's not the - * same as chunkPtr2->nextPtr in the case - * where chunkPtr2 is NULL because the line - * is indented). */ - int leftX; /* The left edge of the region we're - * currently working on. */ - int leftXIn; /* 1 means beveled edge at leftX slopes right - * as it goes down, 0 means it slopes left - * as it goes down. */ - int rightX; /* Right edge of chunkPtr. */ - int rightX2; /* Right edge of chunkPtr2. */ - int matchLeft; /* Does the style of this line match that - * of its neighbor just to the left of - * the current x coordinate? */ - int matchRight; /* Does line's style match its neighbor - * just to the right of the current x-coord? */ - int minX, maxX, xOffset; - StyleValues *sValuePtr; - Display *display; - - /* - * Pass 1: scan through dlPtr from left to right. For each range of - * chunks with the same style, draw the main background for the style - * plus the vertical parts of the 3D borders (the left and right - * edges). - */ - - display = Tk_Display(textPtr->tkwin); - minX = dInfoPtr->curPixelOffset; - xOffset = dInfoPtr->x - minX; - maxX = minX + dInfoPtr->maxX - dInfoPtr->x; - chunkPtr = dlPtr->chunkPtr; - - /* - * Note A: in the following statement, and a few others later in - * this file marked with "See Note A above", the right side of the - * assignment was replaced with 0 on 6/18/97. This has the effect - * of highlighting the empty space to the left of a line whenever - * the leftmost character of the line is highlighted. This way, - * multi-line highlights always line up along their left edges. - * However, this may look funny in the case where a single word is - * highlighted. To undo the change, replace "leftX = 0" with "leftX - * = chunkPtr->x" and "rightX2 = 0" with "rightX2 = nextPtr2->x" - * here and at all the marked points below. This restores the old - * behavior where empty space to the left of a line is not - * highlighted, leaving a ragged left edge for multi-line - * highlights. - */ - - leftX = 0; - for (; leftX < maxX; chunkPtr = chunkPtr->nextPtr) { - if ((chunkPtr->nextPtr != NULL) - && SAME_BACKGROUND(chunkPtr->nextPtr->stylePtr, - chunkPtr->stylePtr)) { - continue; - } - sValuePtr = chunkPtr->stylePtr->sValuePtr; - rightX = chunkPtr->x + chunkPtr->width; - if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) { - rightX = maxX; - } - if (chunkPtr->stylePtr->bgGC != None) { - XFillRectangle(display, pixmap, chunkPtr->stylePtr->bgGC, - leftX + xOffset, 0, (unsigned int) (rightX - leftX), - (unsigned int) dlPtr->height); - if (sValuePtr->relief != TK_RELIEF_FLAT) { - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, 0, sValuePtr->borderWidth, - dlPtr->height, 1, sValuePtr->relief); - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX - sValuePtr->borderWidth + xOffset, - 0, sValuePtr->borderWidth, dlPtr->height, 0, - sValuePtr->relief); - } - } - leftX = rightX; - } - - /* - * Pass 2: draw the horizontal bevels along the top of the line. To - * do this, scan through dlPtr from left to right while simultaneously - * scanning through the line just above dlPtr. ChunkPtr2 and nextPtr2 - * refer to two adjacent chunks in the line above. - */ - - chunkPtr = dlPtr->chunkPtr; - leftX = 0; /* See Note A above. */ - leftXIn = 1; - rightX = chunkPtr->x + chunkPtr->width; - if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) { - rightX = maxX; - } - chunkPtr2 = NULL; - if (prevPtr != NULL) { - /* - * Find the chunk in the previous line that covers leftX. - */ - - nextPtr2 = prevPtr->chunkPtr; - rightX2 = 0; /* See Note A above. */ - while (rightX2 <= leftX) { - chunkPtr2 = nextPtr2; - if (chunkPtr2 == NULL) { - break; - } - nextPtr2 = chunkPtr2->nextPtr; - rightX2 = chunkPtr2->x + chunkPtr2->width; - if (nextPtr2 == NULL) { - rightX2 = INT_MAX; - } - } - } else { - nextPtr2 = NULL; - rightX2 = INT_MAX; - } - - while (leftX < maxX) { - matchLeft = (chunkPtr2 != NULL) - && SAME_BACKGROUND(chunkPtr2->stylePtr, chunkPtr->stylePtr); - sValuePtr = chunkPtr->stylePtr->sValuePtr; - if (rightX <= rightX2) { - /* - * The chunk in our line is about to end. If its style - * changes then draw the bevel for the current style. - */ - - if ((chunkPtr->nextPtr == NULL) - || !SAME_BACKGROUND(chunkPtr->stylePtr, - chunkPtr->nextPtr->stylePtr)) { - if (!matchLeft && (sValuePtr->relief != TK_RELIEF_FLAT)) { - Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, - sValuePtr->border, leftX + xOffset, 0, - rightX - leftX, sValuePtr->borderWidth, leftXIn, - 1, 1, sValuePtr->relief); - } - leftX = rightX; - leftXIn = 1; - - /* - * If the chunk in the line above is also ending at - * the same point then advance to the next chunk in - * that line. - */ - - if ((rightX == rightX2) && (chunkPtr2 != NULL)) { - goto nextChunk2; - } - } - chunkPtr = chunkPtr->nextPtr; - if (chunkPtr == NULL) { - break; - } - rightX = chunkPtr->x + chunkPtr->width; - if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) { - rightX = maxX; - } - continue; - } - - /* - * The chunk in the line above is ending at an x-position where - * there is no change in the style of the current line. If the - * style above matches the current line on one side of the change - * but not on the other, we have to draw an L-shaped piece of - * bevel. - */ - - matchRight = (nextPtr2 != NULL) - && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr); - if (matchLeft && !matchRight) { - if (sValuePtr->relief != TK_RELIEF_FLAT) { - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 - sValuePtr->borderWidth + xOffset, 0, - sValuePtr->borderWidth, sValuePtr->borderWidth, 0, - sValuePtr->relief); - } - leftX = rightX2 - sValuePtr->borderWidth; - leftXIn = 0; - } else if (!matchLeft && matchRight - && (sValuePtr->relief != TK_RELIEF_FLAT)) { - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 + xOffset, 0, sValuePtr->borderWidth, - sValuePtr->borderWidth, 1, sValuePtr->relief); - Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, 0, rightX2 + sValuePtr->borderWidth -leftX, - sValuePtr->borderWidth, leftXIn, 0, 1, - sValuePtr->relief); - } - - nextChunk2: - chunkPtr2 = nextPtr2; - if (chunkPtr2 == NULL) { - rightX2 = INT_MAX; - } else { - nextPtr2 = chunkPtr2->nextPtr; - rightX2 = chunkPtr2->x + chunkPtr2->width; - if (nextPtr2 == NULL) { - rightX2 = INT_MAX; - } - } - } - /* - * Pass 3: draw the horizontal bevels along the bottom of the line. - * This uses the same approach as pass 2. - */ - - chunkPtr = dlPtr->chunkPtr; - leftX = 0; /* See Note A above. */ - leftXIn = 0; - rightX = chunkPtr->x + chunkPtr->width; - if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) { - rightX = maxX; - } - chunkPtr2 = NULL; - if (dlPtr->nextPtr != NULL) { - /* - * Find the chunk in the previous line that covers leftX. - */ - - nextPtr2 = dlPtr->nextPtr->chunkPtr; - rightX2 = 0; /* See Note A above. */ - while (rightX2 <= leftX) { - chunkPtr2 = nextPtr2; - if (chunkPtr2 == NULL) { - break; - } - nextPtr2 = chunkPtr2->nextPtr; - rightX2 = chunkPtr2->x + chunkPtr2->width; - if (nextPtr2 == NULL) { - rightX2 = INT_MAX; - } - } - } else { - nextPtr2 = NULL; - rightX2 = INT_MAX; - } - - while (leftX < maxX) { - matchLeft = (chunkPtr2 != NULL) - && SAME_BACKGROUND(chunkPtr2->stylePtr, chunkPtr->stylePtr); - sValuePtr = chunkPtr->stylePtr->sValuePtr; - if (rightX <= rightX2) { - if ((chunkPtr->nextPtr == NULL) - || !SAME_BACKGROUND(chunkPtr->stylePtr, - chunkPtr->nextPtr->stylePtr)) { - if (!matchLeft && (sValuePtr->relief != TK_RELIEF_FLAT)) { - Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, - sValuePtr->border, leftX + xOffset, - dlPtr->height - sValuePtr->borderWidth, - rightX - leftX, sValuePtr->borderWidth, leftXIn, - 0, 0, sValuePtr->relief); - } - leftX = rightX; - leftXIn = 0; - if ((rightX == rightX2) && (chunkPtr2 != NULL)) { - goto nextChunk2b; - } - } - chunkPtr = chunkPtr->nextPtr; - if (chunkPtr == NULL) { - break; - } - rightX = chunkPtr->x + chunkPtr->width; - if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) { - rightX = maxX; - } - continue; - } - - matchRight = (nextPtr2 != NULL) - && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr); - if (matchLeft && !matchRight) { - if (sValuePtr->relief != TK_RELIEF_FLAT) { - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 - sValuePtr->borderWidth + xOffset, - dlPtr->height - sValuePtr->borderWidth, - sValuePtr->borderWidth, sValuePtr->borderWidth, 0, - sValuePtr->relief); - } - leftX = rightX2 - sValuePtr->borderWidth; - leftXIn = 1; - } else if (!matchLeft && matchRight - && (sValuePtr->relief != TK_RELIEF_FLAT)) { - Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 + xOffset, dlPtr->height - sValuePtr->borderWidth, - sValuePtr->borderWidth, sValuePtr->borderWidth, - 1, sValuePtr->relief); - Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, dlPtr->height - sValuePtr->borderWidth, - rightX2 + sValuePtr->borderWidth - leftX, - sValuePtr->borderWidth, leftXIn, 1, 0, sValuePtr->relief); - } - - nextChunk2b: - chunkPtr2 = nextPtr2; - if (chunkPtr2 == NULL) { - rightX2 = INT_MAX; - } else { - nextPtr2 = chunkPtr2->nextPtr; - rightX2 = chunkPtr2->x + chunkPtr2->width; - if (nextPtr2 == NULL) { - rightX2 = INT_MAX; - } - } - } -} - -/* - *---------------------------------------------------------------------- - * - * DisplayText -- - * - * This procedure is invoked as a when-idle handler to update the - * display. It only redisplays the parts of the text widget that - * are out of date. - * - * Results: - * None. - * - * Side effects: - * Information is redrawn on the screen. - * - *---------------------------------------------------------------------- - */ - -static void -DisplayText(clientData) - ClientData clientData; /* Information about widget. */ -{ - register TkText *textPtr = (TkText *) clientData; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - Tk_Window tkwin; - register DLine *dlPtr; - DLine *prevPtr; - Pixmap pixmap; - int maxHeight, borders; - int bottomY = 0; /* Initialization needed only to stop - * compiler warnings. */ - Tcl_Interp *interp; - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - return; - } - - interp = textPtr->interp; - Tcl_Preserve((ClientData) interp); - - if (tkTextDebug) { - Tcl_SetVar2(interp, "tk_textRelayout", (char *) NULL, "", - TCL_GLOBAL_ONLY); - } - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - - if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) - || (dInfoPtr->maxY <= dInfoPtr->y)) { - UpdateDisplayInfo(textPtr); - dInfoPtr->flags &= ~REDRAW_PENDING; - goto doScrollbars; - } - numRedisplays++; - if (tkTextDebug) { - Tcl_SetVar2(interp, "tk_textRedraw", (char *) NULL, "", - TCL_GLOBAL_ONLY); - } - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - - /* - * Choose a new current item if that is needed (this could cause - * event handlers to be invoked, hence the preserve/release calls - * and the loop, since the handlers could conceivably necessitate - * yet another current item calculation). The tkwin check is because - * the whole window could go away in the Tcl_Release call. - */ - - while (dInfoPtr->flags & REPICK_NEEDED) { - Tcl_Preserve((ClientData) textPtr); - dInfoPtr->flags &= ~REPICK_NEEDED; - TkTextPickCurrent(textPtr, &textPtr->pickEvent); - tkwin = textPtr->tkwin; - Tcl_Release((ClientData) textPtr); - if (tkwin == NULL) { - goto end; - } - } - - /* - * First recompute what's supposed to be displayed. - */ - - UpdateDisplayInfo(textPtr); - dInfoPtr->dLinesInvalidated = 0; - - /* - * See if it's possible to bring some parts of the screen up-to-date - * by scrolling (copying from other parts of the screen). - */ - - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { - register DLine *dlPtr2; - int offset, height, y, oldY; - TkRegion damageRgn; - - if ((dlPtr->oldY == -1) || (dlPtr->y == dlPtr->oldY) - || ((dlPtr->oldY + dlPtr->height) > dInfoPtr->maxY)) { - continue; - } - - /* - * This line is already drawn somewhere in the window so it only - * needs to be copied to its new location. See if there's a group - * of lines that can all be copied together. - */ - - offset = dlPtr->y - dlPtr->oldY; - height = dlPtr->height; - y = dlPtr->y; - for (dlPtr2 = dlPtr->nextPtr; dlPtr2 != NULL; - dlPtr2 = dlPtr2->nextPtr) { - if ((dlPtr2->oldY == -1) - || ((dlPtr2->oldY + offset) != dlPtr2->y) - || ((dlPtr2->oldY + dlPtr2->height) > dInfoPtr->maxY)) { - break; - } - height += dlPtr2->height; - } - - /* - * Reduce the height of the area being copied if necessary to - * avoid overwriting the border area. - */ - - if ((y + height) > dInfoPtr->maxY) { - height = dInfoPtr->maxY -y; - } - oldY = dlPtr->oldY; - - /* - * Update the lines we are going to scroll to show that they - * have been copied. - */ - - while (1) { - dlPtr->oldY = dlPtr->y; - if (dlPtr->nextPtr == dlPtr2) { - break; - } - dlPtr = dlPtr->nextPtr; - } - - /* - * Scan through the lines following the copied ones to see if - * we are going to overwrite them with the copy operation. - * If so, mark them for redisplay. - */ - - for ( ; dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) { - if ((dlPtr2->oldY != -1) - && ((dlPtr2->oldY + dlPtr2->height) > y) - && (dlPtr2->oldY < (y + height))) { - dlPtr2->oldY = -1; - } - } - - /* - * Now scroll the lines. This may generate damage which we - * handle by calling TextInvalidateRegion to mark the display - * blocks as stale. - */ - - damageRgn = TkCreateRegion(); - if (TkScrollWindow(textPtr->tkwin, dInfoPtr->scrollGC, - dInfoPtr->x, oldY, - (dInfoPtr->maxX - dInfoPtr->x), height, - 0, y - oldY, damageRgn)) { - TextInvalidateRegion(textPtr, damageRgn); - } - numCopies++; - TkDestroyRegion(damageRgn); - } - - /* - * Clear the REDRAW_PENDING flag here. This is actually pretty - * tricky. We want to wait until *after* doing the scrolling, - * since that could generate more areas to redraw and don't - * want to reschedule a redisplay for them. On the other hand, - * we can't wait until after all the redisplaying, because the - * act of redisplaying could actually generate more redisplays - * (e.g. in the case of a nested window with event bindings triggered - * by redisplay). - */ - - dInfoPtr->flags &= ~REDRAW_PENDING; - - /* - * Redraw the borders if that's needed. - */ - - if (dInfoPtr->flags & REDRAW_BORDERS) { - if (tkTextDebug) { - Tcl_SetVar2(interp, "tk_textRedraw", (char *) NULL, "borders", - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - } - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - - Tk_Draw3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, textPtr->highlightWidth, - textPtr->highlightWidth, - Tk_Width(textPtr->tkwin) - 2*textPtr->highlightWidth, - Tk_Height(textPtr->tkwin) - 2*textPtr->highlightWidth, - textPtr->borderWidth, textPtr->relief); - if (textPtr->highlightWidth != 0) { - GC gc; - - if (textPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(textPtr->highlightColorPtr, - Tk_WindowId(textPtr->tkwin)); - } else { - gc = Tk_GCForColor(textPtr->highlightBgColorPtr, - Tk_WindowId(textPtr->tkwin)); - } - Tk_DrawFocusHighlight(textPtr->tkwin, gc, textPtr->highlightWidth, - Tk_WindowId(textPtr->tkwin)); - } - borders = textPtr->borderWidth + textPtr->highlightWidth; - if (textPtr->padY > 0) { - Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, borders, borders, - Tk_Width(textPtr->tkwin) - 2*borders, textPtr->padY, - 0, TK_RELIEF_FLAT); - Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, borders, - Tk_Height(textPtr->tkwin) - borders - textPtr->padY, - Tk_Width(textPtr->tkwin) - 2*borders, - textPtr->padY, 0, TK_RELIEF_FLAT); - } - if (textPtr->padX > 0) { - Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, borders, borders + textPtr->padY, - textPtr->padX, - Tk_Height(textPtr->tkwin) - 2*borders -2*textPtr->padY, - 0, TK_RELIEF_FLAT); - Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, - Tk_Width(textPtr->tkwin) - borders - textPtr->padX, - borders + textPtr->padY, textPtr->padX, - Tk_Height(textPtr->tkwin) - 2*borders -2*textPtr->padY, - 0, TK_RELIEF_FLAT); - } - dInfoPtr->flags &= ~REDRAW_BORDERS; - } - - /* - * Now we have to redraw the lines that couldn't be updated by - * scrolling. First, compute the height of the largest line and - * allocate an off-screen pixmap to use for double-buffered - * displays. - */ - - maxHeight = -1; - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; - dlPtr = dlPtr->nextPtr) { - if ((dlPtr->height > maxHeight) && (dlPtr->oldY != dlPtr->y)) { - maxHeight = dlPtr->height; - } - bottomY = dlPtr->y + dlPtr->height; - } - if (maxHeight > dInfoPtr->maxY) { - maxHeight = dInfoPtr->maxY; - } - if (maxHeight > 0) { - pixmap = Tk_GetPixmap(Tk_Display(textPtr->tkwin), - Tk_WindowId(textPtr->tkwin), Tk_Width(textPtr->tkwin), - maxHeight, Tk_Depth(textPtr->tkwin)); - for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr; - (dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY); - prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) { - if (dlPtr->oldY != dlPtr->y) { - if (tkTextDebug) { - char string[TK_POS_CHARS]; - TkTextPrintIndex(&dlPtr->index, string); - Tcl_SetVar2(textPtr->interp, "tk_textRedraw", - (char *) NULL, string, - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - } - DisplayDLine(textPtr, dlPtr, prevPtr, pixmap); - if (dInfoPtr->dLinesInvalidated) { - Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap); - return; - } - dlPtr->oldY = dlPtr->y; - dlPtr->flags &= ~NEW_LAYOUT; - } - } - Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap); - } - - /* - * See if we need to refresh the part of the window below the - * last line of text (if there is any such area). Refresh the - * padding area on the left too, since the insertion cursor might - * have been displayed there previously). - */ - - if (dInfoPtr->topOfEof > dInfoPtr->maxY) { - dInfoPtr->topOfEof = dInfoPtr->maxY; - } - if (bottomY < dInfoPtr->topOfEof) { - if (tkTextDebug) { - Tcl_SetVar2(textPtr->interp, "tk_textRedraw", - (char *) NULL, "eof", - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); - } - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - - Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin), - textPtr->border, dInfoPtr->x - textPtr->padX, bottomY, - dInfoPtr->maxX - (dInfoPtr->x - textPtr->padX), - dInfoPtr->topOfEof-bottomY, 0, TK_RELIEF_FLAT); - } - dInfoPtr->topOfEof = bottomY; - - doScrollbars: - - /* - * Update the vertical scrollbar, if there is one. Note: it's - * important to clear REDRAW_PENDING here, just in case the - * scroll procedure does something that requires redisplay. - */ - - if (textPtr->flags & UPDATE_SCROLLBARS) { - textPtr->flags &= ~UPDATE_SCROLLBARS; - if (textPtr->yScrollCmd != NULL) { - GetYView(textPtr->interp, textPtr, 1); - } - - if (textPtr->tkwin == NULL) { - - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - - /* - * Update the horizontal scrollbar, if any. - */ - - if (textPtr->xScrollCmd != NULL) { - GetXView(textPtr->interp, textPtr, 1); - } - } - -end: - Tcl_Release((ClientData) interp); -} - -/* - *---------------------------------------------------------------------- - * - * TkTextEventuallyRepick -- - * - * This procedure is invoked whenever something happens that - * could change the current character or the tags associated - * with it. - * - * Results: - * None. - * - * Side effects: - * A repick is scheduled as an idle handler. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkTextEventuallyRepick(textPtr) - TkText *textPtr; /* Widget record for text widget. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - - dInfoPtr->flags |= REPICK_NEEDED; - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkTextRedrawRegion -- - * - * This procedure is invoked to schedule a redisplay for a given - * region of a text widget. The redisplay itself may not occur - * immediately: it's scheduled as a when-idle handler. - * - * Results: - * None. - * - * Side effects: - * Information will eventually be redrawn on the screen. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkTextRedrawRegion(textPtr, x, y, width, height) - TkText *textPtr; /* Widget record for text widget. */ - int x, y; /* Coordinates of upper-left corner of area - * to be redrawn, in pixels relative to - * textPtr's window. */ - int width, height; /* Width and height of area to be redrawn. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkRegion damageRgn = TkCreateRegion(); - XRectangle rect; - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - TkUnionRectWithRegion(&rect, damageRgn, damageRgn); - - TextInvalidateRegion(textPtr, damageRgn); - - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - TkDestroyRegion(damageRgn); -} - -/* - *---------------------------------------------------------------------- - * - * TextInvalidateRegion -- - * - * Mark a region of text as invalid. - * - * Results: - * None. - * - * Side effects: - * Updates the display information for the text widget. - * - *---------------------------------------------------------------------- - */ - -static void -TextInvalidateRegion(textPtr, region) - TkText *textPtr; /* Widget record for text widget. */ - TkRegion region; /* Region of area to redraw. */ -{ - register DLine *dlPtr; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - int maxY, inset; - XRectangle rect; - - /* - * Find all lines that overlap the given region and mark them for - * redisplay. - */ - - TkClipBox(region, &rect); - maxY = rect.y + rect.height; - for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; - dlPtr = dlPtr->nextPtr) { - if ((dlPtr->oldY != -1) && (TkRectInRegion(region, rect.x, dlPtr->y, - rect.width, (unsigned int) dlPtr->height) != RectangleOut)) { - dlPtr->oldY = -1; - } - } - if (dInfoPtr->topOfEof < maxY) { - dInfoPtr->topOfEof = maxY; - } - - /* - * Schedule the redisplay operation if there isn't one already - * scheduled. - */ - - inset = textPtr->borderWidth + textPtr->highlightWidth; - if ((rect.x < (inset + textPtr->padX)) - || (rect.y < (inset + textPtr->padY)) - || ((int) (rect.x + rect.width) > (Tk_Width(textPtr->tkwin) - - inset - textPtr->padX)) - || (maxY > (Tk_Height(textPtr->tkwin) - inset - textPtr->padY))) { - dInfoPtr->flags |= REDRAW_BORDERS; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkTextChanged -- - * - * This procedure is invoked when info in a text widget is about - * to be modified in a way that changes how it is displayed (e.g. - * characters were inserted or deleted, or tag information was - * changed). This procedure must be called *before* a change is - * made, so that indexes in the display information are still - * valid. - * - * Results: - * None. - * - * Side effects: - * The range of character between index1Ptr (inclusive) and - * index2Ptr (exclusive) will be redisplayed at some point in the - * future (the actual redisplay is scheduled as a when-idle handler). - * - *---------------------------------------------------------------------- - */ - -void -TkTextChanged(textPtr, index1Ptr, index2Ptr) - TkText *textPtr; /* Widget record for text widget. */ - TkTextIndex *index1Ptr; /* Index of first character to redisplay. */ - TkTextIndex *index2Ptr; /* Index of character just after last one - * to redisplay. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - DLine *firstPtr, *lastPtr; - TkTextIndex rounded; - - /* - * Schedule both a redisplay and a recomputation of display information. - * It's done here rather than the end of the procedure for two reasons: - * - * 1. If there are no display lines to update we'll want to return - * immediately, well before the end of the procedure. - * 2. It's important to arrange for the redisplay BEFORE calling - * FreeDLines. The reason for this is subtle and has to do with - * embedded windows. The chunk delete procedure for an embedded - * window will schedule an idle handler to unmap the window. - * However, we want the idle handler for redisplay to be called - * first, so that it can put the embedded window back on the screen - * again (if appropriate). This will prevent the window from ever - * being unmapped, and thereby avoid flashing. - */ - - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; - - /* - * Find the DLines corresponding to index1Ptr and index2Ptr. There - * is one tricky thing here, which is that we have to relayout in - * units of whole text lines: round index1Ptr back to the beginning - * of its text line, and include all the display lines after index2, - * up to the end of its text line. This is necessary because the - * indices stored in the display lines will no longer be valid. It's - * also needed because any edit could change the way lines wrap. - */ - - rounded = *index1Ptr; - rounded.charIndex = 0; - firstPtr = FindDLine(dInfoPtr->dLinePtr, &rounded); - if (firstPtr == NULL) { - return; - } - lastPtr = FindDLine(dInfoPtr->dLinePtr, index2Ptr); - while ((lastPtr != NULL) - && (lastPtr->index.linePtr == index2Ptr->linePtr)) { - lastPtr = lastPtr->nextPtr; - } - - /* - * Delete all the DLines from firstPtr up to but not including lastPtr. - */ - - FreeDLines(textPtr, firstPtr, lastPtr, 1); -} - -/* - *---------------------------------------------------------------------- - * - * TkTextRedrawTag -- - * - * This procedure is invoked to request a redraw of all characters - * in a given range that have a particular tag on or off. It's - * called, for example, when tag options change. - * - * Results: - * None. - * - * Side effects: - * Information on the screen may be redrawn, and the layout of - * the screen may change. - * - *---------------------------------------------------------------------- - */ - -void -TkTextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag) - TkText *textPtr; /* Widget record for text widget. */ - TkTextIndex *index1Ptr; /* First character in range to consider - * for redisplay. NULL means start at - * beginning of text. */ - TkTextIndex *index2Ptr; /* Character just after last one to consider - * for redisplay. NULL means process all - * the characters in the text. */ - TkTextTag *tagPtr; /* Information about tag. */ - int withTag; /* 1 means redraw characters that have the - * tag, 0 means redraw those without. */ -{ - register DLine *dlPtr; - DLine *endPtr; - int tagOn; - TkTextSearch search; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkTextIndex *curIndexPtr; - TkTextIndex endOfText, *endIndexPtr; - - /* - * Round up the starting position if it's before the first line - * visible on the screen (we only care about what's on the screen). - */ - - dlPtr = dInfoPtr->dLinePtr; - if (dlPtr == NULL) { - return; - } - if ((index1Ptr == NULL) || (TkTextIndexCmp(&dlPtr->index, index1Ptr) > 0)) { - index1Ptr = &dlPtr->index; - } - - /* - * Set the stopping position if it wasn't specified. - */ - - if (index2Ptr == NULL) { - index2Ptr = TkTextMakeIndex(textPtr->tree, - TkBTreeNumLines(textPtr->tree), 0, &endOfText); - } - - /* - * Initialize a search through all transitions on the tag, starting - * with the first transition where the tag's current state is different - * from what it will eventually be. - */ - - TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search); - /* - * Make our own curIndex because at this point search.curIndex - * may not equal index1Ptr->curIndex in the case the first tag toggle - * comes after index1Ptr (See the use of FindTagStart in TkBTreeStartSearch) - */ - curIndexPtr = index1Ptr; - tagOn = TkBTreeCharTagged(index1Ptr, tagPtr); - if (tagOn != withTag) { - if (!TkBTreeNextTag(&search)) { - return; - } - curIndexPtr = &search.curIndex; - } - - /* - * Schedule a redisplay and layout recalculation if they aren't - * already pending. This has to be done before calling FreeDLines, - * for the reason given in TkTextChanged. - */ - - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; - - /* - * Each loop through the loop below is for one range of characters - * where the tag's current state is different than its eventual - * state. At the top of the loop, search contains information about - * the first character in the range. - */ - - while (1) { - /* - * Find the first DLine structure in the range. Note: if the - * desired character isn't the first in its text line, then look - * for the character just before it instead. This is needed to - * handle the case where the first character of a wrapped - * display line just got smaller, so that it now fits on the - * line before: need to relayout the line containing the - * previous character. - */ - - if (curIndexPtr->charIndex == 0) { - dlPtr = FindDLine(dlPtr, curIndexPtr); - } else { - TkTextIndex tmp; - - tmp = *curIndexPtr; - tmp.charIndex -= 1; - dlPtr = FindDLine(dlPtr, &tmp); - } - if (dlPtr == NULL) { - break; - } - - /* - * Find the first DLine structure that's past the end of the range. - */ - - if (!TkBTreeNextTag(&search)) { - endIndexPtr = index2Ptr; - } else { - curIndexPtr = &search.curIndex; - endIndexPtr = curIndexPtr; - } - endPtr = FindDLine(dlPtr, endIndexPtr); - if ((endPtr != NULL) && (endPtr->index.linePtr == endIndexPtr->linePtr) - && (endPtr->index.charIndex < endIndexPtr->charIndex)) { - endPtr = endPtr->nextPtr; - } - - /* - * Delete all of the display lines in the range, so that they'll - * be re-layed out and redrawn. - */ - - FreeDLines(textPtr, dlPtr, endPtr, 1); - dlPtr = endPtr; - - /* - * Find the first text line in the next range. - */ - - if (!TkBTreeNextTag(&search)) { - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkTextRelayoutWindow -- - * - * This procedure is called when something has happened that - * invalidates the whole layout of characters on the screen, such - * as a change in a configuration option for the overall text - * widget or a change in the window size. It causes all display - * information to be recomputed and the window to be redrawn. - * - * Results: - * None. - * - * Side effects: - * All the display information will be recomputed for the window - * and the window will be redrawn. - * - *---------------------------------------------------------------------- - */ - -void -TkTextRelayoutWindow(textPtr) - TkText *textPtr; /* Widget record for text widget. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - GC new; - XGCValues gcValues; - - /* - * Schedule the window redisplay. See TkTextChanged for the - * reason why this has to be done before any calls to FreeDLines. - */ - - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|REDRAW_BORDERS|DINFO_OUT_OF_DATE - |REPICK_NEEDED; - - /* - * (Re-)create the graphics context for drawing the traversal - * highlight. - */ - - gcValues.graphics_exposures = False; - new = Tk_GetGC(textPtr->tkwin, GCGraphicsExposures, &gcValues); - if (dInfoPtr->copyGC != None) { - Tk_FreeGC(textPtr->display, dInfoPtr->copyGC); - } - dInfoPtr->copyGC = new; - - /* - * Throw away all the current layout information. - */ - - FreeDLines(textPtr, dInfoPtr->dLinePtr, (DLine *) NULL, 1); - dInfoPtr->dLinePtr = NULL; - - /* - * Recompute some overall things for the layout. Even if the - * window gets very small, pretend that there's at least one - * pixel of drawing space in it. - */ - - if (textPtr->highlightWidth < 0) { - textPtr->highlightWidth = 0; - } - dInfoPtr->x = textPtr->highlightWidth + textPtr->borderWidth - + textPtr->padX; - dInfoPtr->y = textPtr->highlightWidth + textPtr->borderWidth - + textPtr->padY; - dInfoPtr->maxX = Tk_Width(textPtr->tkwin) - textPtr->highlightWidth - - textPtr->borderWidth - textPtr->padX; - if (dInfoPtr->maxX <= dInfoPtr->x) { - dInfoPtr->maxX = dInfoPtr->x + 1; - } - dInfoPtr->maxY = Tk_Height(textPtr->tkwin) - textPtr->highlightWidth - - textPtr->borderWidth - textPtr->padY; - if (dInfoPtr->maxY <= dInfoPtr->y) { - dInfoPtr->maxY = dInfoPtr->y + 1; - } - dInfoPtr->topOfEof = dInfoPtr->maxY; - - /* - * If the upper-left character isn't the first in a line, recompute - * it. This is necessary because a change in the window's size - * or options could change the way lines wrap. - */ - - if (textPtr->topIndex.charIndex != 0) { - MeasureUp(textPtr, &textPtr->topIndex, 0, &textPtr->topIndex); - } - - /* - * Invalidate cached scrollbar positions, so that scrollbars - * sliders will be udpated. - */ - - dInfoPtr->xScrollFirst = dInfoPtr->xScrollLast = -1; - dInfoPtr->yScrollFirst = dInfoPtr->yScrollLast = -1; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextSetYView -- - * - * This procedure is called to specify what lines are to be - * displayed in a text widget. - * - * Results: - * None. - * - * Side effects: - * The display will (eventually) be updated so that the position - * given by "indexPtr" is visible on the screen at the position - * determined by "pickPlace". - * - *---------------------------------------------------------------------- - */ - -void -TkTextSetYView(textPtr, indexPtr, pickPlace) - TkText *textPtr; /* Widget record for text widget. */ - TkTextIndex *indexPtr; /* Position that is to appear somewhere - * in the view. */ - int pickPlace; /* 0 means topLine must appear at top of - * screen. 1 means we get to pick where it - * appears: minimize screen motion or else - * display line at center of screen. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - register DLine *dlPtr; - int bottomY, close, lineIndex; - TkTextIndex tmpIndex, rounded; - Tk_FontMetrics fm; - - /* - * If the specified position is the extra line at the end of the - * text, round it back to the last real line. - */ - - lineIndex = TkBTreeLineIndex(indexPtr->linePtr); - if (lineIndex == TkBTreeNumLines(indexPtr->tree)) { - TkTextIndexBackChars(indexPtr, 1, &rounded); - indexPtr = &rounded; - } - - if (!pickPlace) { - /* - * The specified position must go at the top of the screen. - * Just leave all the DLine's alone: we may be able to reuse - * some of the information that's currently on the screen - * without redisplaying it all. - */ - - if (indexPtr->charIndex == 0) { - textPtr->topIndex = *indexPtr; - } else { - MeasureUp(textPtr, indexPtr, 0, &textPtr->topIndex); - } - goto scheduleUpdate; - } - - /* - * We have to pick where to display the index. First, bring - * the display information up to date and see if the index will be - * completely visible in the current screen configuration. If so - * then there's nothing to do. - */ - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr); - if (dlPtr != NULL) { - if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { - /* - * Part of the line hangs off the bottom of the screen; - * pretend the whole line is off-screen. - */ - - dlPtr = NULL; - } else if ((dlPtr->index.linePtr == indexPtr->linePtr) - && (dlPtr->index.charIndex <= indexPtr->charIndex)) { - return; - } - } - - /* - * The desired line isn't already on-screen. Figure out what - * it means to be "close" to the top or bottom of the screen. - * Close means within 1/3 of the screen height or within three - * lines, whichever is greater. Add one extra line also, to - * account for the way MeasureUp rounds. - */ - - Tk_GetFontMetrics(textPtr->tkfont, &fm); - bottomY = (dInfoPtr->y + dInfoPtr->maxY + fm.linespace)/2; - close = (dInfoPtr->maxY - dInfoPtr->y)/3; - if (close < 3*fm.linespace) { - close = 3*fm.linespace; - } - close += fm.linespace; - if (dlPtr != NULL) { - /* - * The desired line is above the top of screen. If it is - * "close" to the top of the window then make it the top - * line on the screen. - */ - - MeasureUp(textPtr, &textPtr->topIndex, close, &tmpIndex); - if (TkTextIndexCmp(&tmpIndex, indexPtr) <= 0) { - MeasureUp(textPtr, indexPtr, 0, &textPtr->topIndex); - goto scheduleUpdate; - } - } else { - /* - * The desired line is below the bottom of the screen. If it is - * "close" to the bottom of the screen then position it at the - * bottom of the screen. - */ - - MeasureUp(textPtr, indexPtr, close, &tmpIndex); - if (FindDLine(dInfoPtr->dLinePtr, &tmpIndex) != NULL) { - bottomY = dInfoPtr->maxY - dInfoPtr->y; - } - } - - /* - * Our job now is to arrange the display so that indexPtr appears - * as low on the screen as possible but with its bottom no lower - * than bottomY. BottomY is the bottom of the window if the - * desired line is just below the current screen, otherwise it - * is a half-line lower than the center of the window. - */ - - MeasureUp(textPtr, indexPtr, bottomY, &textPtr->topIndex); - - scheduleUpdate: - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; -} - -/* - *-------------------------------------------------------------- - * - * MeasureUp -- - * - * Given one index, find the index of the first character - * on the highest display line that would be displayed no more - * than "distance" pixels above the given index. - * - * Results: - * *dstPtr is filled in with the index of the first character - * on a display line. The display line is found by measuring - * up "distance" pixels above the pixel just below an imaginary - * display line that contains srcPtr. If the display line - * that covers this coordinate actually extends above the - * coordinate, then return the index of the next lower line - * instead (i.e. the returned index will be completely visible - * at or below the given y-coordinate). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -MeasureUp(textPtr, srcPtr, distance, dstPtr) - TkText *textPtr; /* Text widget in which to measure. */ - TkTextIndex *srcPtr; /* Index of character from which to start - * measuring. */ - int distance; /* Vertical distance in pixels measured - * from the pixel just below the lowest - * one in srcPtr's line. */ - TkTextIndex *dstPtr; /* Index to fill in with result. */ -{ - int lineNum; /* Number of current line. */ - int charsToCount; /* Maximum number of characters to measure - * in current line. */ - TkTextIndex bestIndex; /* Best candidate seen so far for result. */ - TkTextIndex index; - DLine *dlPtr, *lowestPtr; - int noBestYet; /* 1 means bestIndex hasn't been set. */ - - noBestYet = 1; - charsToCount = srcPtr->charIndex + 1; - index.tree = srcPtr->tree; - for (lineNum = TkBTreeLineIndex(srcPtr->linePtr); lineNum >= 0; - lineNum--) { - /* - * Layout an entire text line (potentially > 1 display line). - * For the first line, which contains srcPtr, only layout the - * part up through srcPtr (charsToCount is non-infinite to - * accomplish this). Make a list of all the display lines - * in backwards order (the lowest DLine on the screen is first - * in the list). - */ - - index.linePtr = TkBTreeFindLine(srcPtr->tree, lineNum); - index.charIndex = 0; - lowestPtr = NULL; - do { - dlPtr = LayoutDLine(textPtr, &index); - dlPtr->nextPtr = lowestPtr; - lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) && (index.linePtr == dlPtr->index.linePtr)); - - /* - * Scan through the display lines to see if we've covered enough - * vertical distance. If so, save the starting index for the - * line at the desired location. - */ - - for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { - distance -= dlPtr->height; - if (distance < 0) { - *dstPtr = (noBestYet) ? dlPtr->index : bestIndex; - break; - } - bestIndex = dlPtr->index; - noBestYet = 0; - } - - /* - * Discard the display lines, then either return or prepare - * for the next display line to lay out. - */ - - FreeDLines(textPtr, lowestPtr, (DLine *) NULL, 0); - if (distance < 0) { - return; - } - charsToCount = INT_MAX; /* Consider all chars. in next line. */ - } - - /* - * Ran off the beginning of the text. Return the first character - * in the text. - */ - - TkTextMakeIndex(textPtr->tree, 0, 0, dstPtr); -} - -/* - *-------------------------------------------------------------- - * - * TkTextSeeCmd -- - * - * This procedure is invoked to process the "see" option for - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextSeeCmd(textPtr, interp, argc, argv) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "see". */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkTextIndex index; - int x, y, width, height, lineWidth, charCount, oneThird, delta; - DLine *dlPtr; - TkTextDispChunk *chunkPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " see index\"", (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[2], &index) != TCL_OK) { - return TCL_ERROR; - } - - /* - * If the specified position is the extra line at the end of the - * text, round it back to the last real line. - */ - - if (TkBTreeLineIndex(index.linePtr) == TkBTreeNumLines(index.tree)) { - TkTextIndexBackChars(&index, 1, &index); - } - - /* - * First get the desired position into the vertical range of the window. - */ - - TkTextSetYView(textPtr, &index, 1); - - /* - * Now make sure that the character is in view horizontally. - */ - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - lineWidth = dInfoPtr->maxX - dInfoPtr->x; - if (dInfoPtr->maxLength < lineWidth) { - return TCL_OK; - } - - /* - * Find the chunk that contains the desired index. - */ - - dlPtr = FindDLine(dInfoPtr->dLinePtr, &index); - charCount = index.charIndex - dlPtr->index.charIndex; - for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { - if (charCount < chunkPtr->numChars) { - break; - } - charCount -= chunkPtr->numChars; - } - - /* - * Call a chunk-specific procedure to find the horizontal range of - * the character within the chunk. - */ - - (*chunkPtr->bboxProc)(chunkPtr, charCount, dlPtr->y + dlPtr->spaceAbove, - dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, - dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width, - &height); - delta = x - dInfoPtr->curPixelOffset; - oneThird = lineWidth/3; - if (delta < 0) { - if (delta < -oneThird) { - dInfoPtr->newCharOffset = (x - lineWidth/2)/textPtr->charWidth; - } else { - dInfoPtr->newCharOffset -= ((-delta) + textPtr->charWidth - 1) - / textPtr->charWidth; - } - } else { - delta -= (lineWidth - width); - if (delta > 0) { - if (delta > oneThird) { - dInfoPtr->newCharOffset = (x - lineWidth/2)/textPtr->charWidth; - } else { - dInfoPtr->newCharOffset += (delta + textPtr->charWidth - 1) - / textPtr->charWidth; - } - } else { - return TCL_OK; - } - } - dInfoPtr->flags |= DINFO_OUT_OF_DATE; - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkTextXviewCmd -- - * - * This procedure is invoked to process the "xview" option for - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextXviewCmd(textPtr, interp, argc, argv) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "xview". */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - int type, charsPerPage, count, newOffset; - double fraction; - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - - if (argc == 2) { - GetXView(interp, textPtr, 0); - return TCL_OK; - } - - newOffset = dInfoPtr->newCharOffset; - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - return TCL_ERROR; - case TK_SCROLL_MOVETO: - if (fraction > 1.0) { - fraction = 1.0; - } - if (fraction < 0) { - fraction = 0; - } - newOffset = (int) (((fraction * dInfoPtr->maxLength) / textPtr->charWidth) - + 0.5); - break; - case TK_SCROLL_PAGES: - charsPerPage = ((dInfoPtr->maxX - dInfoPtr->x) / textPtr->charWidth) - - 2; - if (charsPerPage < 1) { - charsPerPage = 1; - } - newOffset += charsPerPage*count; - break; - case TK_SCROLL_UNITS: - newOffset += count; - break; - } - - dInfoPtr->newCharOffset = newOffset; - dInfoPtr->flags |= DINFO_OUT_OF_DATE; - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * ScrollByLines -- - * - * This procedure is called to scroll a text widget up or down - * by a given number of lines. - * - * Results: - * None. - * - * Side effects: - * The view in textPtr's window changes to reflect the value - * of "offset". - * - *---------------------------------------------------------------------- - */ - -static void -ScrollByLines(textPtr, offset) - TkText *textPtr; /* Widget to scroll. */ - int offset; /* Amount by which to scroll, in *screen* - * lines. Positive means that information - * later in text becomes visible, negative - * means that information earlier in the - * text becomes visible. */ -{ - int i, charsToCount, lineNum; - TkTextIndex new, index; - TkTextLine *lastLinePtr; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - DLine *dlPtr, *lowestPtr; - - if (offset < 0) { - /* - * Must scroll up (to show earlier information in the text). - * The code below is similar to that in MeasureUp, except that - * it counts lines instead of pixels. - */ - - charsToCount = textPtr->topIndex.charIndex + 1; - index.tree = textPtr->tree; - offset--; /* Skip line containing topIndex. */ - for (lineNum = TkBTreeLineIndex(textPtr->topIndex.linePtr); - lineNum >= 0; lineNum--) { - index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); - index.charIndex = 0; - lowestPtr = NULL; - do { - dlPtr = LayoutDLine(textPtr, &index); - dlPtr->nextPtr = lowestPtr; - lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) - && (index.linePtr == dlPtr->index.linePtr)); - - for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { - offset++; - if (offset == 0) { - textPtr->topIndex = dlPtr->index; - break; - } - } - - /* - * Discard the display lines, then either return or prepare - * for the next display line to lay out. - */ - - FreeDLines(textPtr, lowestPtr, (DLine *) NULL, 0); - if (offset >= 0) { - goto scheduleUpdate; - } - charsToCount = INT_MAX; - } - - /* - * Ran off the beginning of the text. Return the first character - * in the text. - */ - - TkTextMakeIndex(textPtr->tree, 0, 0, &textPtr->topIndex); - } else { - /* - * Scrolling down, to show later information in the text. - * Just count lines from the current top of the window. - */ - - lastLinePtr = TkBTreeFindLine(textPtr->tree, - TkBTreeNumLines(textPtr->tree)); - for (i = 0; i < offset; i++) { - dlPtr = LayoutDLine(textPtr, &textPtr->topIndex); - dlPtr->nextPtr = NULL; - TkTextIndexForwChars(&textPtr->topIndex, dlPtr->count, &new); - FreeDLines(textPtr, dlPtr, (DLine *) NULL, 0); - if (new.linePtr == lastLinePtr) { - break; - } - textPtr->topIndex = new; - } - } - - scheduleUpdate: - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; -} - -/* - *-------------------------------------------------------------- - * - * TkTextYviewCmd -- - * - * This procedure is invoked to process the "yview" option for - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextYviewCmd(textPtr, interp, argc, argv) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "yview". */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - int pickPlace, lineNum, type, charsInLine; - Tk_FontMetrics fm; - int pixels, count; - size_t switchLength; - double fraction; - TkTextIndex index, new; - TkTextLine *lastLinePtr; - DLine *dlPtr; - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - - if (argc == 2) { - GetYView(interp, textPtr, 0); - return TCL_OK; - } - - /* - * Next, handle the old syntax: "pathName yview ?-pickplace? where" - */ - - pickPlace = 0; - if (argv[2][0] == '-') { - switchLength = strlen(argv[2]); - if ((switchLength >= 2) - && (strncmp(argv[2], "-pickplace", switchLength) == 0)) { - pickPlace = 1; - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " yview -pickplace lineNum|index\"", - (char *) NULL); - return TCL_ERROR; - } - } - } - if ((argc == 3) || pickPlace) { - if (Tcl_GetInt(interp, argv[2+pickPlace], &lineNum) == TCL_OK) { - TkTextMakeIndex(textPtr->tree, lineNum, 0, &index); - TkTextSetYView(textPtr, &index, 0); - return TCL_OK; - } - - /* - * The argument must be a regular text index. - */ - - Tcl_ResetResult(interp); - if (TkTextGetIndex(interp, textPtr, argv[2+pickPlace], - &index) != TCL_OK) { - return TCL_ERROR; - } - TkTextSetYView(textPtr, &index, pickPlace); - return TCL_OK; - } - - /* - * New syntax: dispatch based on argv[2]. - */ - - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - return TCL_ERROR; - case TK_SCROLL_MOVETO: - if (fraction > 1.0) { - fraction = 1.0; - } - if (fraction < 0) { - fraction = 0; - } - fraction *= TkBTreeNumLines(textPtr->tree); - lineNum = (int) fraction; - TkTextMakeIndex(textPtr->tree, lineNum, 0, &index); - charsInLine = TkBTreeCharsInLine(index.linePtr); - index.charIndex = (int)((charsInLine * (fraction-lineNum)) + 0.5); - if (index.charIndex >= charsInLine) { - TkTextMakeIndex(textPtr->tree, lineNum+1, 0, &index); - } - TkTextSetYView(textPtr, &index, 0); - break; - case TK_SCROLL_PAGES: - /* - * Scroll up or down by screenfuls. Actually, use the - * window height minus two lines, so that there's some - * overlap between adjacent pages. - */ - - Tk_GetFontMetrics(textPtr->tkfont, &fm); - if (count < 0) { - pixels = (dInfoPtr->maxY - 2*fm.linespace - dInfoPtr->y)*(-count) - + fm.linespace; - MeasureUp(textPtr, &textPtr->topIndex, pixels, &new); - if (TkTextIndexCmp(&textPtr->topIndex, &new) == 0) { - /* - * A page of scrolling ended up being less than one line. - * Scroll one line anyway. - */ - - count = -1; - goto scrollByLines; - } - textPtr->topIndex = new; - } else { - /* - * Scrolling down by pages. Layout lines starting at the - * top index and count through the desired vertical distance. - */ - - pixels = (dInfoPtr->maxY - 2*fm.linespace - dInfoPtr->y)*count; - lastLinePtr = TkBTreeFindLine(textPtr->tree, - TkBTreeNumLines(textPtr->tree)); - do { - dlPtr = LayoutDLine(textPtr, &textPtr->topIndex); - dlPtr->nextPtr = NULL; - TkTextIndexForwChars(&textPtr->topIndex, dlPtr->count, - &new); - pixels -= dlPtr->height; - FreeDLines(textPtr, dlPtr, (DLine *) NULL, 0); - if (new.linePtr == lastLinePtr) { - break; - } - textPtr->topIndex = new; - } while (pixels > 0); - } - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; - break; - case TK_SCROLL_UNITS: - scrollByLines: - ScrollByLines(textPtr, count); - break; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkTextScanCmd -- - * - * This procedure is invoked to process the "scan" option for - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextScanCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "scan". */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkTextIndex index; - int c, x, y, totalScroll, newChar, maxChar; - Tk_FontMetrics fm; - size_t length; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) { - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[4], &y) != TCL_OK) { - return TCL_ERROR; - } - c = argv[2][0]; - length = strlen(argv[2]); - if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { - /* - * Amplify the difference between the current position and the - * mark position to compute how much the view should shift, then - * update the mark position to correspond to the new view. If we - * run off the edge of the text, reset the mark point so that the - * current position continues to correspond to the edge of the - * window. This means that the picture will start dragging as - * soon as the mouse reverses direction (without this reset, might - * have to slide mouse a long ways back before the picture starts - * moving again). - */ - - newChar = dInfoPtr->scanMarkChar + (10*(dInfoPtr->scanMarkX - x)) - / (textPtr->charWidth); - maxChar = 1 + (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) - + textPtr->charWidth - 1)/textPtr->charWidth; - if (newChar < 0) { - dInfoPtr->scanMarkChar = newChar = 0; - dInfoPtr->scanMarkX = x; - } else if (newChar > maxChar) { - dInfoPtr->scanMarkChar = newChar = maxChar; - dInfoPtr->scanMarkX = x; - } - dInfoPtr->newCharOffset = newChar; - - Tk_GetFontMetrics(textPtr->tkfont, &fm); - totalScroll = (10*(dInfoPtr->scanMarkY - y)) / fm.linespace; - if (totalScroll != dInfoPtr->scanTotalScroll) { - index = textPtr->topIndex; - ScrollByLines(textPtr, totalScroll-dInfoPtr->scanTotalScroll); - dInfoPtr->scanTotalScroll = totalScroll; - if ((index.linePtr == textPtr->topIndex.linePtr) && - (index.charIndex == textPtr->topIndex.charIndex)) { - dInfoPtr->scanTotalScroll = 0; - dInfoPtr->scanMarkY = y; - } - } - } else if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { - dInfoPtr->scanMarkChar = dInfoPtr->newCharOffset; - dInfoPtr->scanMarkX = x; - dInfoPtr->scanTotalScroll = 0; - dInfoPtr->scanMarkY = y; - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - return TCL_ERROR; - } - dInfoPtr->flags |= DINFO_OUT_OF_DATE; - if (!(dInfoPtr->flags & REDRAW_PENDING)) { - dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * GetXView -- - * - * This procedure computes the fractions that indicate what's - * visible in a text window and, optionally, evaluates a - * Tcl script to report them to the text's associated scrollbar. - * - * Results: - * If report is zero, then interp->result is filled in with - * two real numbers separated by a space, giving the position of - * the left and right edges of the window as fractions from 0 to - * 1, where 0 means the left edge of the text and 1 means the right - * edge. If report is non-zero, then interp->result isn't modified - * directly, but instead a script is evaluated in interp to report - * the new horizontal scroll position to the scrollbar (if the scroll - * position hasn't changed then no script is invoked). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -GetXView(interp, textPtr, report) - Tcl_Interp *interp; /* If "report" is FALSE, string - * describing visible range gets - * stored in interp->result. */ - TkText *textPtr; /* Information about text widget. */ - int report; /* Non-zero means report info to - * scrollbar if it has changed. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - char buffer[200]; - double first, last; - int code; - - if (dInfoPtr->maxLength > 0) { - first = ((double) dInfoPtr->curPixelOffset) - / dInfoPtr->maxLength; - last = first + ((double) (dInfoPtr->maxX - dInfoPtr->x)) - / dInfoPtr->maxLength; - if (last > 1.0) { - last = 1.0; - } - } else { - first = 0; - last = 1.0; - } - if (!report) { - sprintf(interp->result, "%g %g", first, last); - return; - } - if ((first == dInfoPtr->xScrollFirst) && (last == dInfoPtr->xScrollLast)) { - return; - } - dInfoPtr->xScrollFirst = first; - dInfoPtr->xScrollLast = last; - sprintf(buffer, " %g %g", first, last); - code = Tcl_VarEval(interp, textPtr->xScrollCmd, - buffer, (char *) NULL); - if (code != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (horizontal scrolling command executed by text)"); - Tcl_BackgroundError(interp); - } -} - -/* - *---------------------------------------------------------------------- - * - * GetYView -- - * - * This procedure computes the fractions that indicate what's - * visible in a text window and, optionally, evaluates a - * Tcl script to report them to the text's associated scrollbar. - * - * Results: - * If report is zero, then interp->result is filled in with - * two real numbers separated by a space, giving the position of - * the top and bottom of the window as fractions from 0 to 1, where - * 0 means the beginning of the text and 1 means the end. If - * report is non-zero, then interp->result isn't modified directly, - * but a script is evaluated in interp to report the new scroll - * position to the scrollbar (if the scroll position hasn't changed - * then no script is invoked). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -GetYView(interp, textPtr, report) - Tcl_Interp *interp; /* If "report" is FALSE, string - * describing visible range gets - * stored in interp->result. */ - TkText *textPtr; /* Information about text widget. */ - int report; /* Non-zero means report info to - * scrollbar if it has changed. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - char buffer[200]; - double first, last; - DLine *dlPtr; - int totalLines, code, count; - - dlPtr = dInfoPtr->dLinePtr; - totalLines = TkBTreeNumLines(textPtr->tree); - first = ((double) TkBTreeLineIndex(dlPtr->index.linePtr)) - + ((double) dlPtr->index.charIndex) - / (TkBTreeCharsInLine(dlPtr->index.linePtr)); - first /= totalLines; - while (1) { - if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { - /* - * The last line is only partially visible, so don't - * count its characters in what's visible. - */ - count = 0; - break; - } - if (dlPtr->nextPtr == NULL) { - count = dlPtr->count; - break; - } - dlPtr = dlPtr->nextPtr; - } - last = ((double) TkBTreeLineIndex(dlPtr->index.linePtr)) - + ((double) (dlPtr->index.charIndex + count)) - / (TkBTreeCharsInLine(dlPtr->index.linePtr)); - last /= totalLines; - if (!report) { - sprintf(interp->result, "%g %g", first, last); - return; - } - if ((first == dInfoPtr->yScrollFirst) && (last == dInfoPtr->yScrollLast)) { - return; - } - dInfoPtr->yScrollFirst = first; - dInfoPtr->yScrollLast = last; - sprintf(buffer, " %g %g", first, last); - code = Tcl_VarEval(interp, textPtr->yScrollCmd, - buffer, (char *) NULL); - if (code != TCL_OK) { - Tcl_AddErrorInfo(interp, - "\n (vertical scrolling command executed by text)"); - Tcl_BackgroundError(interp); - } -} - -/* - *---------------------------------------------------------------------- - * - * FindDLine -- - * - * This procedure is called to find the DLine corresponding to a - * given text index. - * - * Results: - * The return value is a pointer to the first DLine found in the - * list headed by dlPtr that displays information at or after the - * specified position. If there is no such line in the list then - * NULL is returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static DLine * -FindDLine(dlPtr, indexPtr) - register DLine *dlPtr; /* Pointer to first in list of DLines - * to search. */ - TkTextIndex *indexPtr; /* Index of desired character. */ -{ - TkTextLine *linePtr; - - if (dlPtr == NULL) { - return NULL; - } - if (TkBTreeLineIndex(indexPtr->linePtr) - < TkBTreeLineIndex(dlPtr->index.linePtr)) { - /* - * The first display line is already past the desired line. - */ - return dlPtr; - } - - /* - * Find the first display line that covers the desired text line. - */ - - linePtr = dlPtr->index.linePtr; - while (linePtr != indexPtr->linePtr) { - while (dlPtr->index.linePtr == linePtr) { - dlPtr = dlPtr->nextPtr; - if (dlPtr == NULL) { - return NULL; - } - } - linePtr = TkBTreeNextLine(linePtr); - if (linePtr == NULL) { - panic("FindDLine reached end of text"); - } - } - if (indexPtr->linePtr != dlPtr->index.linePtr) { - return dlPtr; - } - - /* - * Now get to the right position within the text line. - */ - - while (indexPtr->charIndex >= (dlPtr->index.charIndex + dlPtr->count)) { - dlPtr = dlPtr->nextPtr; - if ((dlPtr == NULL) || (dlPtr->index.linePtr != indexPtr->linePtr)) { - break; - } - } - return dlPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextPixelIndex -- - * - * Given an (x,y) coordinate on the screen, find the location of - * the character closest to that location. - * - * Results: - * The index at *indexPtr is modified to refer to the character - * on the display that is closest to (x,y). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkTextPixelIndex(textPtr, x, y, indexPtr) - TkText *textPtr; /* Widget record for text widget. */ - int x, y; /* Pixel coordinates of point in widget's - * window. */ - TkTextIndex *indexPtr; /* This index gets filled in with the - * index of the character nearest to (x,y). */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - register DLine *dlPtr; - register TkTextDispChunk *chunkPtr; - - /* - * Make sure that all of the layout information about what's - * displayed where on the screen is up-to-date. - */ - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - - /* - * If the coordinates are above the top of the window, then adjust - * them to refer to the upper-right corner of the window. If they're - * off to one side or the other, then adjust to the closest side. - */ - - if (y < dInfoPtr->y) { - y = dInfoPtr->y; - x = dInfoPtr->x; - } - if (x >= dInfoPtr->maxX) { - x = dInfoPtr->maxX - 1; - } - if (x < dInfoPtr->x) { - x = dInfoPtr->x; - } - - /* - * Find the display line containing the desired y-coordinate. - */ - - for (dlPtr = dInfoPtr->dLinePtr; y >= (dlPtr->y + dlPtr->height); - dlPtr = dlPtr->nextPtr) { - if (dlPtr->nextPtr == NULL) { - /* - * Y-coordinate is off the bottom of the displayed text. - * Use the last character on the last line. - */ - - x = dInfoPtr->maxX - 1; - break; - } - } - - /* - * Scan through the line's chunks to find the one that contains - * the desired x-coordinate. Before doing this, translate the - * x-coordinate from the coordinate system of the window to the - * coordinate system of the line (to take account of x-scrolling). - */ - - *indexPtr = dlPtr->index; - x = x - dInfoPtr->x + dInfoPtr->curPixelOffset; - for (chunkPtr = dlPtr->chunkPtr; x >= (chunkPtr->x + chunkPtr->width); - indexPtr->charIndex += chunkPtr->numChars, - chunkPtr = chunkPtr->nextPtr) { - if (chunkPtr->nextPtr == NULL) { - indexPtr->charIndex += chunkPtr->numChars - 1; - return; - } - } - - /* - * If the chunk has more than one character in it, ask it which - * character is at the desired location. - */ - - if (chunkPtr->numChars > 1) { - indexPtr->charIndex += (*chunkPtr->measureProc)(chunkPtr, x); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkTextCharBbox -- - * - * Given an index, find the bounding box of the screen area - * occupied by that character. - * - * Results: - * Zero is returned if the character is on the screen. -1 - * means the character isn't on the screen. If the return value - * is 0, then the bounding box of the part of the character that's - * visible on the screen is returned to *xPtr, *yPtr, *widthPtr, - * and *heightPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkTextCharBbox(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr) - TkText *textPtr; /* Widget record for text widget. */ - TkTextIndex *indexPtr; /* Index of character whose bounding - * box is desired. */ - int *xPtr, *yPtr; /* Filled with character's upper-left - * coordinate. */ - int *widthPtr, *heightPtr; /* Filled in with character's dimensions. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - DLine *dlPtr; - register TkTextDispChunk *chunkPtr; - int index; - - /* - * Make sure that all of the screen layout information is up to date. - */ - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - - /* - * Find the display line containing the desired index. - */ - - dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr); - if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) { - return -1; - } - - /* - * Find the chunk within the line that contains the desired - * index. - */ - - index = indexPtr->charIndex - dlPtr->index.charIndex; - for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { - if (chunkPtr == NULL) { - return -1; - } - if (index < chunkPtr->numChars) { - break; - } - index -= chunkPtr->numChars; - } - - /* - * Call a chunk-specific procedure to find the horizontal range of - * the character within the chunk, then fill in the vertical range. - * The x-coordinate returned by bboxProc is a coordinate within a - * line, not a coordinate on the screen. Translate it to reflect - * horizontal scrolling. - */ - - (*chunkPtr->bboxProc)(chunkPtr, index, dlPtr->y + dlPtr->spaceAbove, - dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, - dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr, - heightPtr); - *xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curPixelOffset; - if ((index == (chunkPtr->numChars-1)) && (chunkPtr->nextPtr == NULL)) { - /* - * Last character in display line. Give it all the space up to - * the line. - */ - - if (*xPtr > dInfoPtr->maxX) { - *xPtr = dInfoPtr->maxX; - } - *widthPtr = dInfoPtr->maxX - *xPtr; - } - if ((*xPtr + *widthPtr) <= dInfoPtr->x) { - return -1; - } - if ((*xPtr + *widthPtr) > dInfoPtr->maxX) { - *widthPtr = dInfoPtr->maxX - *xPtr; - if (*widthPtr <= 0) { - return -1; - } - } - if ((*yPtr + *heightPtr) > dInfoPtr->maxY) { - *heightPtr = dInfoPtr->maxY - *yPtr; - if (*heightPtr <= 0) { - return -1; - } - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextDLineInfo -- - * - * Given an index, return information about the display line - * containing that character. - * - * Results: - * Zero is returned if the character is on the screen. -1 - * means the character isn't on the screen. If the return value - * is 0, then information is returned in the variables pointed - * to by xPtr, yPtr, widthPtr, heightPtr, and basePtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) - TkText *textPtr; /* Widget record for text widget. */ - TkTextIndex *indexPtr; /* Index of character whose bounding - * box is desired. */ - int *xPtr, *yPtr; /* Filled with line's upper-left - * coordinate. */ - int *widthPtr, *heightPtr; /* Filled in with line's dimensions. */ - int *basePtr; /* Filled in with the baseline position, - * measured as an offset down from *yPtr. */ -{ - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - DLine *dlPtr; - - /* - * Make sure that all of the screen layout information is up to date. - */ - - if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { - UpdateDisplayInfo(textPtr); - } - - /* - * Find the display line containing the desired index. - */ - - dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr); - if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) { - return -1; - } - - *xPtr = dInfoPtr->x - dInfoPtr->curPixelOffset + dlPtr->chunkPtr->x; - *widthPtr = dlPtr->length - dlPtr->chunkPtr->x; - *yPtr = dlPtr->y; - if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { - *heightPtr = dInfoPtr->maxY - dlPtr->y; - } else { - *heightPtr = dlPtr->height; - } - *basePtr = dlPtr->baseline; - return 0; -} - -/* - *-------------------------------------------------------------- - * - * TkTextCharLayoutProc -- - * - * This procedure is the "layoutProc" for character segments. - * - * Results: - * If there is something to display for the chunk then a - * non-zero value is returned and the fields of chunkPtr - * will be filled in (see the declaration of TkTextDispChunk - * in tkText.h for details). If zero is returned it means - * that no characters from this chunk fit in the window. - * If -1 is returned it means that this segment just doesn't - * need to be displayed (never happens for text). - * - * Side effects: - * Memory is allocated to hold additional information about - * the chunk. - * - *-------------------------------------------------------------- - */ - -int -TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, - noCharsYet, wrapMode, chunkPtr) - TkText *textPtr; /* Text widget being layed out. */ - TkTextIndex *indexPtr; /* Index of first character to lay out - * (corresponds to segPtr and offset). */ - TkTextSegment *segPtr; /* Segment being layed out. */ - int offset; /* Offset within segment of first character - * to consider. */ - int maxX; /* Chunk must not occupy pixels at this - * position or higher. */ - int maxChars; /* Chunk must not include more than this - * many characters. */ - int noCharsYet; /* Non-zero means no characters have been - * assigned to this display line yet. */ - Tk_Uid wrapMode; /* How to handle line wrapping: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ - register TkTextDispChunk *chunkPtr; - /* Structure to fill in with information - * about this chunk. The x field has already - * been set by the caller. */ -{ - Tk_Font tkfont; - int nextX, charsThatFit, count; - CharInfo *ciPtr; - char *p; - TkTextSegment *nextPtr; - Tk_FontMetrics fm; - - /* - * Figure out how many characters will fit in the space we've got. - * Include the next character, even though it won't fit completely, - * if any of the following is true: - * (a) the chunk contains no characters and the display line contains - * no characters yet (i.e. the line isn't wide enough to hold - * even a single character). - * (b) at least one pixel of the character is visible, we haven't - * already exceeded the character limit, and the next character - * is a white space character. - */ - - p = segPtr->body.chars + offset; - tkfont = chunkPtr->stylePtr->sValuePtr->tkfont; - charsThatFit = MeasureChars(tkfont, p, maxChars, chunkPtr->x, maxX, 0, - &nextX); - if (charsThatFit < maxChars) { - if ((charsThatFit == 0) && noCharsYet) { - charsThatFit = 1; - MeasureChars(tkfont, p, 1, chunkPtr->x, INT_MAX, 0, &nextX); - } - if ((nextX < maxX) && ((p[charsThatFit] == ' ') - || (p[charsThatFit] == '\t'))) { - /* - * Space characters are funny, in that they are considered - * to fit if there is at least one pixel of space left on the - * line. Just give the space character whatever space is left. - */ - - nextX = maxX; - charsThatFit++; - } - if (p[charsThatFit] == '\n') { - /* - * A newline character takes up no space, so if the previous - * character fits then so does the newline. - */ - - charsThatFit++; - } - if (charsThatFit == 0) { - return 0; - } - } - - Tk_GetFontMetrics(tkfont, &fm); - - /* - * Fill in the chunk structure and allocate and initialize a - * CharInfo structure. If the last character is a newline - * then don't bother to display it. - */ - - chunkPtr->displayProc = CharDisplayProc; - chunkPtr->undisplayProc = CharUndisplayProc; - chunkPtr->measureProc = CharMeasureProc; - chunkPtr->bboxProc = CharBboxProc; - chunkPtr->numChars = charsThatFit; - chunkPtr->minAscent = fm.ascent + chunkPtr->stylePtr->sValuePtr->offset; - chunkPtr->minDescent = fm.descent - chunkPtr->stylePtr->sValuePtr->offset; - chunkPtr->minHeight = 0; - chunkPtr->width = nextX - chunkPtr->x; - chunkPtr->breakIndex = -1; - ciPtr = (CharInfo *) ckalloc((unsigned) - (sizeof(CharInfo) - 3 + charsThatFit)); - chunkPtr->clientData = (ClientData) ciPtr; - ciPtr->numChars = charsThatFit; - strncpy(ciPtr->chars, p, (size_t) charsThatFit); - if (p[charsThatFit-1] == '\n') { - ciPtr->numChars--; - } - - /* - * Compute a break location. If we're in word wrap mode, a - * break can occur after any space character, or at the end of - * the chunk if the next segment (ignoring those with zero size) - * is not a character segment. - */ - - if (wrapMode != tkTextWordUid) { - chunkPtr->breakIndex = chunkPtr->numChars; - } else { - for (count = charsThatFit, p += charsThatFit-1; count > 0; - count--, p--) { - if (isspace(UCHAR(*p))) { - chunkPtr->breakIndex = count; - break; - } - } - if ((charsThatFit+offset) == segPtr->size) { - for (nextPtr = segPtr->nextPtr; nextPtr != NULL; - nextPtr = nextPtr->nextPtr) { - if (nextPtr->size != 0) { - if (nextPtr->typePtr != &tkTextCharType) { - chunkPtr->breakIndex = chunkPtr->numChars; - } - break; - } - } - } - } - return 1; -} - -/* - *-------------------------------------------------------------- - * - * CharDisplayProc -- - * - * This procedure is called to display a character chunk on - * the screen or in an off-screen pixmap. - * - * Results: - * None. - * - * Side effects: - * Graphics are drawn. - * - *-------------------------------------------------------------- - */ - -static void -CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) - TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */ - int x; /* X-position in dst at which to - * draw this chunk (may differ from - * the x-position in the chunk because - * of scrolling). */ - int y; /* Y-position at which to draw this - * chunk in dst. */ - int height; /* Total height of line. */ - int baseline; /* Offset of baseline from y. */ - Display *display; /* Display to use for drawing. */ - Drawable dst; /* Pixmap or window in which to draw - * chunk. */ - int screenY; /* Y-coordinate in text window that - * corresponds to y. */ -{ - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; - TextStyle *stylePtr; - StyleValues *sValuePtr; - int offsetChars, offsetX; - - if ((x + chunkPtr->width) <= 0) { - /* - * The chunk is off-screen. - */ - - return; - } - - stylePtr = chunkPtr->stylePtr; - sValuePtr = stylePtr->sValuePtr; - - /* - * If the text sticks out way to the left of the window, skip - * over the characters that aren't in the visible part of the - * window. This is essential if x is very negative (such as - * less than 32K); otherwise overflow problems will occur - * in servers that use 16-bit arithmetic, like X. - */ - - offsetX = x; - offsetChars = 0; - if (x < 0) { - offsetChars = MeasureChars(sValuePtr->tkfont, ciPtr->chars, - ciPtr->numChars, x, 0, x - chunkPtr->x, &offsetX); - } - - /* - * Draw the text, underline, and overstrike for this chunk. - */ - - if (ciPtr->numChars > offsetChars) { - int numChars = ciPtr->numChars - offsetChars; - char *string = ciPtr->chars + offsetChars; - - if ((numChars > 0) && (string[numChars - 1] == '\t')) { - numChars--; - } - Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string, - numChars, offsetX, y + baseline - sValuePtr->offset); - if (sValuePtr->underline) { - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, - ciPtr->chars + offsetChars, offsetX, - y + baseline - sValuePtr->offset, - 0, numChars); - - } - if (sValuePtr->overstrike) { - Tk_FontMetrics fm; - - Tk_GetFontMetrics(sValuePtr->tkfont, &fm); - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, - ciPtr->chars + offsetChars, offsetX, - y + baseline - sValuePtr->offset - - fm.descent - (fm.ascent * 3) / 10, - 0, numChars); - } - } -} - -/* - *-------------------------------------------------------------- - * - * CharUndisplayProc -- - * - * This procedure is called when a character chunk is no - * longer going to be displayed. It frees up resources - * that were allocated to display the chunk. - * - * Results: - * None. - * - * Side effects: - * Memory and other resources get freed. - * - *-------------------------------------------------------------- - */ - -static void -CharUndisplayProc(textPtr, chunkPtr) - TkText *textPtr; /* Overall information about text - * widget. */ - TkTextDispChunk *chunkPtr; /* Chunk that is about to be freed. */ -{ - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; - - ckfree((char *) ciPtr); -} - -/* - *-------------------------------------------------------------- - * - * CharMeasureProc -- - * - * This procedure is called to determine which character in - * a character chunk lies over a given x-coordinate. - * - * Results: - * The return value is the index *within the chunk* of the - * character that covers the position given by "x". - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -CharMeasureProc(chunkPtr, x) - TkTextDispChunk *chunkPtr; /* Chunk containing desired coord. */ - int x; /* X-coordinate, in same coordinate - * system as chunkPtr->x. */ -{ - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; - int endX; - - return MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, - chunkPtr->numChars-1, chunkPtr->x, x, 0, &endX); -} - -/* - *-------------------------------------------------------------- - * - * CharBboxProc -- - * - * This procedure is called to compute the bounding box of - * the area occupied by a single character. - * - * Results: - * There is no return value. *xPtr and *yPtr are filled in - * with the coordinates of the upper left corner of the - * character, and *widthPtr and *heightPtr are filled in with - * the dimensions of the character in pixels. Note: not all - * of the returned bbox is necessarily visible on the screen - * (the rightmost part might be off-screen to the right, - * and the bottommost part might be off-screen to the bottom). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -CharBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, - widthPtr, heightPtr) - TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ - int index; /* Index of desired character within - * the chunk. */ - int y; /* Topmost pixel in area allocated - * for this line. */ - int lineHeight; /* Height of line, in pixels. */ - int baseline; /* Location of line's baseline, in - * pixels measured down from y. */ - int *xPtr, *yPtr; /* Gets filled in with coords of - * character's upper-left pixel. - * X-coord is in same coordinate - * system as chunkPtr->x. */ - int *widthPtr; /* Gets filled in with width of - * character, in pixels. */ - int *heightPtr; /* Gets filled in with height of - * character, in pixels. */ -{ - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; - int maxX; - - maxX = chunkPtr->width + chunkPtr->x; - MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, index, - chunkPtr->x, 1000000, 0, xPtr); - - if (index == ciPtr->numChars) { - /* - * This situation only happens if the last character in a line - * is a space character, in which case it absorbs all of the - * extra space in the line (see TkTextCharLayoutProc). - */ - - *widthPtr = maxX - *xPtr; - } else if ((ciPtr->chars[index] == '\t') - && (index == (ciPtr->numChars-1))) { - /* - * The desired character is a tab character that terminates a - * chunk; give it all the space left in the chunk. - */ - - *widthPtr = maxX - *xPtr; - } else { - MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars + index, 1, *xPtr, 1000000, 0, widthPtr); - if (*widthPtr > maxX) { - *widthPtr = maxX - *xPtr; - } else { - *widthPtr -= *xPtr; - } - } - *yPtr = y + baseline - chunkPtr->minAscent; - *heightPtr = chunkPtr->minAscent + chunkPtr->minDescent; -} - -/* - *---------------------------------------------------------------------- - * - * AdjustForTab -- - * - * This procedure is called to move a series of chunks right - * in order to align them with a tab stop. - * - * Results: - * None. - * - * Side effects: - * The width of chunkPtr gets adjusted so that it absorbs the - * extra space due to the tab. The x locations in all the chunks - * after chunkPtr are adjusted rightward to align with the tab - * stop given by tabArrayPtr and index. - * - *---------------------------------------------------------------------- - */ - -static void -AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) - TkText *textPtr; /* Information about the text widget as - * a whole. */ - TkTextTabArray *tabArrayPtr; /* Information about the tab stops - * that apply to this line. May be - * NULL to indicate default tabbing - * (every 8 chars). */ - int index; /* Index of current tab stop. */ - TkTextDispChunk *chunkPtr; /* Chunk whose last character is - * the tab; the following chunks - * contain information to be shifted - * right. */ - -{ - int x, desired, delta, width, decimal, i, gotDigit; - TkTextDispChunk *chunkPtr2, *decimalChunkPtr; - CharInfo *ciPtr; - int tabX, prev, spaceWidth; - char *p; - TkTextTabAlign alignment; - - if (chunkPtr->nextPtr == NULL) { - /* - * Nothing after the actual tab; just return. - */ - - return; - } - - /* - * If no tab information has been given, do the usual thing: - * round up to the next boundary of 8 average-sized characters. - */ - - x = chunkPtr->nextPtr->x; - if ((tabArrayPtr == NULL) || (tabArrayPtr->numTabs == 0)) { - /* - * No tab information has been given, so use the default - * interpretation of tabs. - */ - - desired = NextTabStop(textPtr->tkfont, x, 0); - goto update; - } - - if (index < tabArrayPtr->numTabs) { - alignment = tabArrayPtr->tabs[index].alignment; - tabX = tabArrayPtr->tabs[index].location; - } else { - /* - * Ran out of tab stops; compute a tab position by extrapolating - * from the last two tab positions. - */ - - if (tabArrayPtr->numTabs > 1) { - prev = tabArrayPtr->tabs[tabArrayPtr->numTabs-2].location; - } else { - prev = 0; - } - alignment = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].alignment; - tabX = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].location - + (index + 1 - tabArrayPtr->numTabs) - * (tabArrayPtr->tabs[tabArrayPtr->numTabs-1].location - prev); - } - - if (alignment == LEFT) { - desired = tabX; - goto update; - } - - if ((alignment == CENTER) || (alignment == RIGHT)) { - /* - * Compute the width of all the information in the tab group, - * then use it to pick a desired location. - */ - - width = 0; - for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; - chunkPtr2 = chunkPtr2->nextPtr) { - width += chunkPtr2->width; - } - if (alignment == CENTER) { - desired = tabX - width/2; - } else { - desired = tabX - width; - } - goto update; - } - - /* - * Must be numeric alignment. Search through the text to be - * tabbed, looking for the last , or . before the first character - * that isn't a number, comma, period, or sign. - */ - - decimalChunkPtr = NULL; - decimal = gotDigit = 0; - for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; - chunkPtr2 = chunkPtr2->nextPtr) { - if (chunkPtr2->displayProc != CharDisplayProc) { - continue; - } - ciPtr = (CharInfo *) chunkPtr2->clientData; - for (p = ciPtr->chars, i = 0; i < ciPtr->numChars; p++, i++) { - if (isdigit(UCHAR(*p))) { - gotDigit = 1; - } else if ((*p == '.') || (*p == ',')) { - decimal = p-ciPtr->chars; - decimalChunkPtr = chunkPtr2; - } else if (gotDigit) { - if (decimalChunkPtr == NULL) { - decimal = p-ciPtr->chars; - decimalChunkPtr = chunkPtr2; - } - goto endOfNumber; - } - } - } - endOfNumber: - if (decimalChunkPtr != NULL) { - int curX; - - ciPtr = (CharInfo *) decimalChunkPtr->clientData; - MeasureChars(decimalChunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars, decimal, decimalChunkPtr->x, 1000000, 0, &curX); - desired = tabX - (curX - x); - goto update; - } else { - /* - * There wasn't a decimal point. Right justify the text. - */ - - width = 0; - for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; - chunkPtr2 = chunkPtr2->nextPtr) { - width += chunkPtr2->width; - } - desired = tabX - width; - } - - /* - * Shift all of the chunks to the right so that the left edge is - * at the desired location, then expand the chunk containing the - * tab. Be sure that the tab occupies at least the width of a - * space character. - */ - - update: - delta = desired - x; - MeasureChars(textPtr->tkfont, " ", 1, 0, INT_MAX, 0, &spaceWidth); - if (delta < spaceWidth) { - delta = spaceWidth; - } - for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; - chunkPtr2 = chunkPtr2->nextPtr) { - chunkPtr2->x += delta; - } - chunkPtr->width += delta; -} - -/* - *---------------------------------------------------------------------- - * - * SizeOfTab -- - * - * This returns an estimate of the amount of white space that will - * be consumed by a tab. - * - * Results: - * The return value is the minimum number of pixels that will - * be occupied by the index'th tab of tabArrayPtr, assuming that - * the current position on the line is x and the end of the - * line is maxX. For numeric tabs, this is a conservative - * estimate. The return value is always >= 0. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -SizeOfTab(textPtr, tabArrayPtr, index, x, maxX) - TkText *textPtr; /* Information about the text widget as - * a whole. */ - TkTextTabArray *tabArrayPtr; /* Information about the tab stops - * that apply to this line. NULL - * means use default tabbing (every - * 8 chars.) */ - int index; /* Index of current tab stop. */ - int x; /* Current x-location in line. Only - * used if tabArrayPtr == NULL. */ - int maxX; /* X-location of pixel just past the - * right edge of the line. */ -{ - int tabX, prev, result, spaceWidth; - TkTextTabAlign alignment; - - if ((tabArrayPtr == NULL) || (tabArrayPtr->numTabs == 0)) { - tabX = NextTabStop(textPtr->tkfont, x, 0); - return tabX - x; - } - if (index < tabArrayPtr->numTabs) { - tabX = tabArrayPtr->tabs[index].location; - alignment = tabArrayPtr->tabs[index].alignment; - } else { - /* - * Ran out of tab stops; compute a tab position by extrapolating - * from the last two tab positions. - */ - - if (tabArrayPtr->numTabs > 1) { - prev = tabArrayPtr->tabs[tabArrayPtr->numTabs-2].location; - } else { - prev = 0; - } - tabX = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].location - + (index + 1 - tabArrayPtr->numTabs) - * (tabArrayPtr->tabs[tabArrayPtr->numTabs-1].location - prev); - alignment = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].alignment; - } - if (alignment == CENTER) { - /* - * Be very careful in the arithmetic below, because maxX may - * be the largest positive number: watch out for integer - * overflow. - */ - - if ((maxX-tabX) < (tabX - x)) { - result = (maxX - x) - 2*(maxX - tabX); - } else { - result = 0; - } - goto done; - } - if (alignment == RIGHT) { - result = 0; - goto done; - } - - /* - * Note: this treats NUMERIC alignment the same as LEFT - * alignment, which is somewhat conservative. However, it's - * pretty tricky at this point to figure out exactly where - * the damn decimal point will be. - */ - - if (tabX > x) { - result = tabX - x; - } else { - result = 0; - } - - done: - MeasureChars(textPtr->tkfont, " ", 1, 0, INT_MAX, 0, &spaceWidth); - if (result < spaceWidth) { - result = spaceWidth; - } - return result; -} - -/* - *--------------------------------------------------------------------------- - * - * NextTabStop -- - * - * Given the current position, determine where the next default - * tab stop would be located. This procedure is called when the - * current chunk in the text has no tabs defined and so the default - * tab spacing for the font should be used. - * - * Results: - * The location in pixels of the next tab stop. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -NextTabStop(tkfont, x, tabOrigin) - Tk_Font tkfont; /* Font in which chunk that contains tab - * stop will be drawn. */ - int x; /* X-position in pixels where last - * character was drawn. The next tab stop - * occurs somewhere after this location. */ - int tabOrigin; /* The origin for tab stops. May be - * non-zero if text has been scrolled. */ -{ - int tabWidth, rem; - - tabWidth = Tk_TextWidth(tkfont, "0", 1) * 8; - if (tabWidth == 0) { - tabWidth = 1; - } - - x += tabWidth; - rem = (x - tabOrigin) % tabWidth; - if (rem < 0) { - rem += tabWidth; - } - x -= rem; - return x; -} - -/* - *--------------------------------------------------------------------------- - * - * MeasureChars -- - * - * Determine the number of characters from the string that will fit - * in the given horizontal span. The measurement is done under the - * assumption that Tk_DisplayChars will be used to actually display - * the characters. - * - * If tabs are encountered in the string, they will be expanded - * to the next tab stop, unless the TK_IGNORE_TABS flag is specified. - * - * If a newline is encountered in the string, the line will be - * broken at that point, unless the TK_NEWSLINES_NOT_SPECIAL flag - * is specified. - * - * Results: - * The return value is the number of characters from source - * that fit in the span given by startX and maxX. *nextXPtr - * is filled in with the x-coordinate at which the first - * character that didn't fit would be drawn, if it were to - * be drawn. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -MeasureChars(tkfont, source, maxChars, startX, maxX, tabOrigin, nextXPtr) - Tk_Font tkfont; /* Font in which to draw characters. */ - CONST char *source; /* Characters to be displayed. Need not - * be NULL-terminated. */ - int maxChars; /* Maximum # of characters to consider from - * source. */ - int startX; /* X-position at which first character will - * be drawn. */ - int maxX; /* Don't consider any character that would - * cross this x-position. */ - int tabOrigin; /* X-location that serves as "origin" for - * tab stops. */ - int *nextXPtr; /* Return x-position of terminating - * character here. */ -{ - int curX, width, ch; - CONST char *special, *end, *start; - - ch = 0; /* lint. */ - curX = startX; - special = source; - end = source + maxChars; - for (start = source; start < end; ) { - if (start >= special) { - /* - * Find the next special character in the string. - */ - - for (special = start; special < end; special++) { - ch = *special; - if ((ch == '\t') || (ch == '\n')) { - break; - } - } - } - - /* - * Special points at the next special character (or the end of the - * string). Process characters between start and special. - */ - - if (curX >= maxX) { - break; - } - start += Tk_MeasureChars(tkfont, start, special - start, maxX - curX, - 0, &width); - curX += width; - if (start < special) { - /* - * No more chars fit in line. - */ - - break; - } - if (special < end) { - if (ch == '\t') { - start++; - } else { - break; - } - } - } - - *nextXPtr = curX; - return start - source; -} diff --git a/generic/tkTextImage.c b/generic/tkTextImage.c deleted file mode 100644 index 06aff3c..0000000 --- a/generic/tkTextImage.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * tkImage.c -- - * - * This file contains code that allows images to be - * nested inside text widgets. It also implements the "image" - * widget command for texts. - * - * Copyright (c) 1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextImage.c,v 1.2 1998/09/14 18:23:19 stanton Exp $ - */ - -#include "tk.h" -#include "tkText.h" -#include "tkPort.h" - -/* - * Definitions for alignment values: - */ - -#define ALIGN_BOTTOM 0 -#define ALIGN_CENTER 1 -#define ALIGN_TOP 2 -#define ALIGN_BASELINE 3 - -/* - * Macro that determines the size of an embedded image segment: - */ - -#define EI_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + sizeof(TkTextEmbImage))) - -/* - * Prototypes for procedures defined in this file: - */ - -static int AlignParseProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, - char *widgRec, int offset)); -static char * AlignPrintProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin, char *widgRec, int offset, - Tcl_FreeProc **freeProcPtr)); -static TkTextSegment * EmbImageCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static void EmbImageCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static void EmbImageBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, - int index, int y, int lineHeight, int baseline, - int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -static int EmbImageConfigure _ANSI_ARGS_((TkText *textPtr, - TkTextSegment *eiPtr, int argc, char **argv)); -static int EmbImageDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -static void EmbImageDisplayProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int x, int y, - int lineHeight, int baseline, Display *display, - Drawable dst, int screenY)); -static int EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, TkTextSegment *segPtr, - int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, - TkTextDispChunk *chunkPtr)); -static void EmbImageProc _ANSI_ARGS_((ClientData clientData, - int x, int y, int width, int height, - int imageWidth, int imageHeight)); - -/* - * The following structure declares the "embedded image" segment type. - */ - -static Tk_SegType tkTextEmbImageType = { - "image", /* name */ - 0, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - EmbImageDeleteProc, /* deleteProc */ - EmbImageCleanupProc, /* cleanupProc */ - (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */ - EmbImageLayoutProc, /* layoutProc */ - EmbImageCheckProc /* checkProc */ -}; - -/* - * Information used for parsing image configuration options: - */ - -static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc, - (ClientData) NULL}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL, - "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption}, - {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextEmbImage, padX), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextEmbImage, padY), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextEmbImage, imageString), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextEmbImage, imageName), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - *-------------------------------------------------------------- - * - * TkTextImageCmd -- - * - * This procedure implements the "image" widget command - * for text widgets. See the user documentation for details - * on what it does. - * - * Results: - * A standard Tcl result or error. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextImageCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "image". */ -{ - size_t length; - register TkTextSegment *eiPtr; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " image option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - length = strlen(argv[2]); - if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) { - TkTextIndex index; - TkTextSegment *eiPtr; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " image cget index option\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - eiPtr = TkTextIndexToSeg(&index, (int *) NULL); - if (eiPtr->typePtr != &tkTextEmbImageType) { - Tcl_AppendResult(interp, "no embedded image at index \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs, - (char *) &eiPtr->body.ei, argv[4], 0); - } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) { - TkTextIndex index; - TkTextSegment *eiPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " image configure index ?option value ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - eiPtr = TkTextIndexToSeg(&index, (int *) NULL); - if (eiPtr->typePtr != &tkTextEmbImageType) { - Tcl_AppendResult(interp, "no embedded image at index \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 4) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) &eiPtr->body.ei, (char *) NULL, 0); - } else if (argc == 5) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) &eiPtr->body.ei, argv[4], 0); - } else { - TkTextChanged(textPtr, &index, &index); - return EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4); - } - } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) { - TkTextIndex index; - int lineIndex; - - /* - * Add a new image. Find where to put the new image, and - * mark that position for redisplay. - */ - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " image create index ?option value ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Don't allow insertions on the last (dummy) line of the text. - */ - - lineIndex = TkBTreeLineIndex(index.linePtr); - if (lineIndex == TkBTreeNumLines(textPtr->tree)) { - lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index); - } - - /* - * Create the new image segment and initialize it. - */ - - eiPtr = (TkTextSegment *) ckalloc(EI_SEG_SIZE); - eiPtr->typePtr = &tkTextEmbImageType; - eiPtr->size = 1; - eiPtr->body.ei.textPtr = textPtr; - eiPtr->body.ei.linePtr = NULL; - eiPtr->body.ei.imageName = NULL; - eiPtr->body.ei.imageString = NULL; - eiPtr->body.ei.name = NULL; - eiPtr->body.ei.image = NULL; - eiPtr->body.ei.align = ALIGN_CENTER; - eiPtr->body.ei.padX = eiPtr->body.ei.padY = 0; - eiPtr->body.ei.chunkCount = 0; - - /* - * Link the segment into the text widget, then configure it (delete - * it again if the configuration fails). - */ - - TkTextChanged(textPtr, &index, &index); - TkBTreeLinkSegment(eiPtr, &index); - if (EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4) != TCL_OK) { - TkTextIndex index2; - - TkTextIndexForwChars(&index, 1, &index2); - TkBTreeDeleteChars(&index, &index2); - return TCL_ERROR; - } - } else if (strncmp(argv[2], "names", length) == 0) { - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " image names\"", (char *) NULL); - return TCL_ERROR; - } - for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, - Tcl_GetHashKey(&textPtr->markTable, hPtr)); - } - } else { - Tcl_AppendResult(interp, "bad image option \"", argv[2], - "\": must be cget, configure, create, or names", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * EmbImageConfigure -- - * - * This procedure is called to handle configuration options - * for an embedded image, using an argc/argv list. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message.. - * - * Side effects: - * Configuration information for the embedded image changes, - * such as alignment, or name of the image. - * - *-------------------------------------------------------------- - */ - -static int -EmbImageConfigure(textPtr, eiPtr, argc, argv) - TkText *textPtr; /* Information about text widget that - * contains embedded image. */ - TkTextSegment *eiPtr; /* Embedded image to be configured. */ - int argc; /* Number of strings in argv. */ - char **argv; /* Array of strings describing configuration - * options. */ -{ - Tk_Image image; - Tcl_DString newName; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - int new; - char *name; - int count = 0; /* The counter for picking a unique name */ - int conflict = 0; /* True if we have a name conflict */ - unsigned int len; /* length of image name */ - - if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs, - argc, argv, (char *) &eiPtr->body.ei,TK_CONFIG_ARGV_ONLY) - != TCL_OK) { - return TCL_ERROR; - } - - /* - * Create the image. Save the old image around and don't free it - * until after the new one is allocated. This keeps the reference - * count from going to zero so the image doesn't have to be recreated - * if it hasn't changed. - */ - - if (eiPtr->body.ei.imageString != NULL) { - image = Tk_GetImage(textPtr->interp, textPtr->tkwin, eiPtr->body.ei.imageString, - EmbImageProc, (ClientData) eiPtr); - if (image == NULL) { - return TCL_ERROR; - } - } else { - image = NULL; - } - if (eiPtr->body.ei.image != NULL) { - Tk_FreeImage(eiPtr->body.ei.image); - } - eiPtr->body.ei.image = image; - - if (eiPtr->body.ei.name != NULL) { - return TCL_OK; - } - - /* - * Find a unique name for this image. Use imageName (or imageString) - * if available, otherwise tack on a #nn and use it. If a name is already - * associated with this image, delete the name. - */ - - name = eiPtr->body.ei.imageName; - if (name == NULL) { - name = eiPtr->body.ei.imageString; - } - if (name == NULL) { - Tcl_AppendResult(textPtr->interp,"Either a \"-name\" ", - "or a \"-image\" argument must be provided ", - "to the \"image create\" subcommand.", - (char *) NULL); - return TCL_ERROR; - } - len = strlen(name); - for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr); - if (strncmp(name, haveName, len) == 0) { - new = 0; - sscanf(haveName+len,"#%d",&new); - if (new > count) { - count = new; - } - if (len == (int) strlen(haveName)) { - conflict = 1; - } - } - } - - Tcl_DStringInit(&newName); - Tcl_DStringAppend(&newName,name, -1); - - if (conflict) { - char buf[10]; - sprintf(buf, "#%d",count+1); - Tcl_DStringAppend(&newName,buf, -1); - } - name = Tcl_DStringValue(&newName); - hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new); - Tcl_SetHashValue(hPtr, eiPtr); - Tcl_AppendResult(textPtr->interp, name , (char *) NULL); - eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1); - strcpy(eiPtr->body.ei.name,name); - Tcl_DStringFree(&newName); - - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * AlignParseProc -- - * - * This procedure is invoked by Tk_ConfigureWidget during - * option processing to handle "-align" options for embedded - * images. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * The alignment for the embedded image may change. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -AlignParseProc(clientData, interp, tkwin, value, widgRec, offset) - ClientData clientData; /* Not used.*/ - Tcl_Interp *interp; /* Used for reporting errors. */ - Tk_Window tkwin; /* Window for text widget. */ - char *value; /* Value of option. */ - char *widgRec; /* Pointer to TkTextEmbWindow - * structure. */ - int offset; /* Offset into item (ignored). */ -{ - register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec; - - if (strcmp(value, "baseline") == 0) { - embPtr->align = ALIGN_BASELINE; - } else if (strcmp(value, "bottom") == 0) { - embPtr->align = ALIGN_BOTTOM; - } else if (strcmp(value, "center") == 0) { - embPtr->align = ALIGN_CENTER; - } else if (strcmp(value, "top") == 0) { - embPtr->align = ALIGN_TOP; - } else { - Tcl_AppendResult(interp, "bad alignment \"", value, - "\": must be baseline, bottom, center, or top", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * AlignPrintProc -- - * - * This procedure is invoked by the Tk configuration code - * to produce a printable string for the "-align" configuration - * option for embedded images. - * - * Results: - * The return value is a string describing the embedded - * images's current alignment. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) - ClientData clientData; /* Ignored. */ - Tk_Window tkwin; /* Window for text widget. */ - char *widgRec; /* Pointer to TkTextEmbImage - * structure. */ - int offset; /* Ignored. */ - Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with - * information about how to reclaim - * storage for return string. */ -{ - switch (((TkTextEmbImage *) widgRec)->align) { - case ALIGN_BASELINE: - return "baseline"; - case ALIGN_BOTTOM: - return "bottom"; - case ALIGN_CENTER: - return "center"; - case ALIGN_TOP: - return "top"; - default: - return "??"; - } -} - -/* - *-------------------------------------------------------------- - * - * EmbImageDeleteProc -- - * - * This procedure is invoked by the text B-tree code whenever - * an embedded image lies in a range of characters being deleted. - * - * Results: - * Returns 0 to indicate that the deletion has been accepted. - * - * Side effects: - * The embedded image is deleted, if it exists, and any resources - * associated with it are released. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -EmbImageDeleteProc(eiPtr, linePtr, treeGone) - TkTextSegment *eiPtr; /* Segment being deleted. */ - TkTextLine *linePtr; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ -{ - Tcl_HashEntry *hPtr; - - if (eiPtr->body.ei.image != NULL) { - hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable, - eiPtr->body.ei.name); - if (hPtr != NULL) { - /* - * (It's possible for there to be no hash table entry for this - * image, if an error occurred while creating the image segment - * but before the image got added to the table) - */ - - Tcl_DeleteHashEntry(hPtr); - } - Tk_FreeImage(eiPtr->body.ei.image); - } - Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei, - eiPtr->body.ei.textPtr->display, 0); - if (eiPtr->body.ei.name != NULL) { - ckfree(eiPtr->body.ei.name); - } - ckfree((char *) eiPtr); - return 0; -} - -/* - *-------------------------------------------------------------- - * - * EmbImageCleanupProc -- - * - * This procedure is invoked by the B-tree code whenever a - * segment containing an embedded image is moved from one - * line to another. - * - * Results: - * None. - * - * Side effects: - * The linePtr field of the segment gets updated. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -EmbImageCleanupProc(eiPtr, linePtr) - TkTextSegment *eiPtr; /* Mark segment that's being moved. */ - TkTextLine *linePtr; /* Line that now contains segment. */ -{ - eiPtr->body.ei.linePtr = linePtr; - return eiPtr; -} - -/* - *-------------------------------------------------------------- - * - * EmbImageLayoutProc -- - * - * This procedure is the "layoutProc" for embedded image - * segments. - * - * Results: - * 1 is returned to indicate that the segment should be - * displayed. The chunkPtr structure is filled in. - * - * Side effects: - * None, except for filling in chunkPtr. - * - *-------------------------------------------------------------- - */ - - /*ARGSUSED*/ -static int -EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, - noCharsYet, wrapMode, chunkPtr) - TkText *textPtr; /* Text widget being layed out. */ - TkTextIndex *indexPtr; /* Identifies first character in chunk. */ - TkTextSegment *eiPtr; /* Segment corresponding to indexPtr. */ - int offset; /* Offset within segPtr corresponding to - * indexPtr (always 0). */ - int maxX; /* Chunk must not occupy pixels at this - * position or higher. */ - int maxChars; /* Chunk must not include more than this - * many characters. */ - int noCharsYet; /* Non-zero means no characters have been - * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ - register TkTextDispChunk *chunkPtr; - /* Structure to fill in with information - * about this chunk. The x field has already - * been set by the caller. */ -{ - int width, height; - - if (offset != 0) { - panic("Non-zero offset in EmbImageLayoutProc"); - } - - /* - * See if there's room for this image on this line. - */ - - if (eiPtr->body.ei.image == NULL) { - width = 0; - height = 0; - } else { - Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height); - width += 2*eiPtr->body.ei.padX; - height += 2*eiPtr->body.ei.padY; - } - if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) { - return 0; - } - - /* - * Fill in the chunk structure. - */ - - chunkPtr->displayProc = EmbImageDisplayProc; - chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL; - chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; - chunkPtr->bboxProc = EmbImageBboxProc; - chunkPtr->numChars = 1; - if (eiPtr->body.ei.align == ALIGN_BASELINE) { - chunkPtr->minAscent = height - eiPtr->body.ei.padY; - chunkPtr->minDescent = eiPtr->body.ei.padY; - chunkPtr->minHeight = 0; - } else { - chunkPtr->minAscent = 0; - chunkPtr->minDescent = 0; - chunkPtr->minHeight = height; - } - chunkPtr->width = width; - chunkPtr->breakIndex = -1; - chunkPtr->breakIndex = 1; - chunkPtr->clientData = (ClientData) eiPtr; - eiPtr->body.ei.chunkCount += 1; - return 1; -} - -/* - *-------------------------------------------------------------- - * - * EmbImageCheckProc -- - * - * This procedure is invoked by the B-tree code to perform - * consistency checks on embedded images. - * - * Results: - * None. - * - * Side effects: - * The procedure panics if it detects anything wrong with - * the embedded image. - * - *-------------------------------------------------------------- - */ - -static void -EmbImageCheckProc(eiPtr, linePtr) - TkTextSegment *eiPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ -{ - if (eiPtr->nextPtr == NULL) { - panic("EmbImageCheckProc: embedded image is last segment in line"); - } - if (eiPtr->size != 1) { - panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size); - } -} - -/* - *-------------------------------------------------------------- - * - * EmbImageDisplayProc -- - * - * This procedure is invoked by the text displaying code - * when it is time to actually draw an embedded image - * chunk on the screen. - * - * Results: - * None. - * - * Side effects: - * The embedded image gets moved to the correct location - * and drawn onto the display. - * - *-------------------------------------------------------------- - */ - -static void -EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY) - TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */ - int x; /* X-position in dst at which to - * draw this chunk (differs from - * the x-position in the chunk because - * of scrolling). */ - int y; /* Top of rectangular bounding box - * for line: tells where to draw this - * chunk in dst (x-position is in - * the chunk itself). */ - int lineHeight; /* Total height of line. */ - int baseline; /* Offset of baseline from y. */ - Display *display; /* Display to use for drawing. */ - Drawable dst; /* Pixmap or window in which to draw */ - int screenY; /* Y-coordinate in text window that - * corresponds to y. */ -{ - TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData; - int lineX, imageX, imageY, width, height; - Tk_Image image; - - image = eiPtr->body.ei.image; - if (image == NULL) { - return; - } - if ((x + chunkPtr->width) <= 0) { - return; - } - - /* - * Compute the image's location and size in the text widget, taking - * into account the align value for the image. - */ - - EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX, - &imageY, &width, &height); - imageX = lineX - chunkPtr->x + x; - - Tk_RedrawImage(image, 0, 0, width, height, dst, - imageX, imageY); -} - -/* - *-------------------------------------------------------------- - * - * EmbImageBboxProc -- - * - * This procedure is called to compute the bounding box of - * the area occupied by an embedded image. - * - * Results: - * There is no return value. *xPtr and *yPtr are filled in - * with the coordinates of the upper left corner of the - * image, and *widthPtr and *heightPtr are filled in with - * the dimensions of the image in pixels. Note: not all - * of the returned bbox is necessarily visible on the screen - * (the rightmost part might be off-screen to the right, - * and the bottommost part might be off-screen to the bottom). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, - widthPtr, heightPtr) - TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ - int index; /* Index of desired character within - * the chunk. */ - int y; /* Topmost pixel in area allocated - * for this line. */ - int lineHeight; /* Total height of line. */ - int baseline; /* Location of line's baseline, in - * pixels measured down from y. */ - int *xPtr, *yPtr; /* Gets filled in with coords of - * character's upper-left pixel. */ - int *widthPtr; /* Gets filled in with width of - * character, in pixels. */ - int *heightPtr; /* Gets filled in with height of - * character, in pixels. */ -{ - TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData; - Tk_Image image; - - image = eiPtr->body.ei.image; - if (image != NULL) { - Tk_SizeOfImage(image, widthPtr, heightPtr); - } else { - *widthPtr = 0; - *heightPtr = 0; - } - *xPtr = chunkPtr->x + eiPtr->body.ei.padX; - switch (eiPtr->body.ei.align) { - case ALIGN_BOTTOM: - *yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY); - break; - case ALIGN_CENTER: - *yPtr = y + (lineHeight - *heightPtr)/2; - break; - case ALIGN_TOP: - *yPtr = y + eiPtr->body.ei.padY; - break; - case ALIGN_BASELINE: - *yPtr = y + (baseline - *heightPtr); - break; - } -} - -/* - *-------------------------------------------------------------- - * - * TkTextImageIndex -- - * - * Given the name of an embedded image within a text widget, - * returns an index corresponding to the image's position - * in the text. - * - * Results: - * The return value is 1 if there is an embedded image by - * the given name in the text widget, 0 otherwise. If the - * image exists, *indexPtr is filled in with its index. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextImageIndex(textPtr, name, indexPtr) - TkText *textPtr; /* Text widget containing image. */ - char *name; /* Name of image. */ - TkTextIndex *indexPtr; /* Index information gets stored here. */ -{ - Tcl_HashEntry *hPtr; - TkTextSegment *eiPtr; - - hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name); - if (hPtr == NULL) { - return 0; - } - eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - indexPtr->tree = textPtr->tree; - indexPtr->linePtr = eiPtr->body.ei.linePtr; - indexPtr->charIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr); - return 1; -} - -/* - *-------------------------------------------------------------- - * - * EmbImageProc -- - * - * This procedure is called by the image code whenever an - * image or its contents changes. - * - * Results: - * None. - * - * Side effects: - * The image will be redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight) - ClientData clientData; /* Pointer to widget record. */ - int x, y; /* Upper left pixel (within image) - * that must be redisplayed. */ - int width, height; /* Dimensions of area to redisplay - * (may be <= 0). */ - int imgWidth, imgHeight; /* New dimensions of image. */ - -{ - TkTextSegment *eiPtr = (TkTextSegment *) clientData; - TkTextIndex index; - - index.tree = eiPtr->body.ei.textPtr->tree; - index.linePtr = eiPtr->body.ei.linePtr; - index.charIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr); - TkTextChanged(eiPtr->body.ei.textPtr, &index, &index); -} diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c deleted file mode 100644 index 4d2ac8e..0000000 --- a/generic/tkTextIndex.c +++ /dev/null @@ -1,840 +0,0 @@ -/* - * tkTextIndex.c -- - * - * This module provides procedures that manipulate indices for - * text widgets. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextIndex.c,v 1.2 1998/09/14 18:23:19 stanton Exp $ - */ - -#include "default.h" -#include "tkPort.h" -#include "tkInt.h" -#include "tkText.h" - -/* - * Index to use to select last character in line (very large integer): - */ - -#define LAST_CHAR 1000000 - -/* - * Forward declarations for procedures defined later in this file: - */ - -static char * ForwBack _ANSI_ARGS_((char *string, - TkTextIndex *indexPtr)); -static char * StartEnd _ANSI_ARGS_(( char *string, - TkTextIndex *indexPtr)); - -/* - *-------------------------------------------------------------- - * - * TkTextMakeIndex -- - * - * Given a line index and a character index, look things up - * in the B-tree and fill in a TkTextIndex structure. - * - * Results: - * The structure at *indexPtr is filled in with information - * about the character at lineIndex and charIndex (or the - * closest existing character, if the specified one doesn't - * exist), and indexPtr is returned as result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -TkTextIndex * -TkTextMakeIndex(tree, lineIndex, charIndex, indexPtr) - TkTextBTree tree; /* Tree that lineIndex and charIndex refer - * to. */ - int lineIndex; /* Index of desired line (0 means first - * line of text). */ - int charIndex; /* Index of desired character. */ - TkTextIndex *indexPtr; /* Structure to fill in. */ -{ - register TkTextSegment *segPtr; - int index; - - indexPtr->tree = tree; - if (lineIndex < 0) { - lineIndex = 0; - charIndex = 0; - } - if (charIndex < 0) { - charIndex = 0; - } - indexPtr->linePtr = TkBTreeFindLine(tree, lineIndex); - if (indexPtr->linePtr == NULL) { - indexPtr->linePtr = TkBTreeFindLine(tree, TkBTreeNumLines(tree)); - charIndex = 0; - } - - /* - * Verify that the index is within the range of the line. - * If not, just use the index of the last character in the line. - */ - - for (index = 0, segPtr = indexPtr->linePtr->segPtr; ; - segPtr = segPtr->nextPtr) { - if (segPtr == NULL) { - indexPtr->charIndex = index-1; - break; - } - index += segPtr->size; - if (index > charIndex) { - indexPtr->charIndex = charIndex; - break; - } - } - return indexPtr; -} - -/* - *-------------------------------------------------------------- - * - * TkTextIndexToSeg -- - * - * Given an index, this procedure returns the segment and - * offset within segment for the index. - * - * Results: - * The return value is a pointer to the segment referred to - * by indexPtr; this will always be a segment with non-zero - * size. The variable at *offsetPtr is set to hold the - * integer offset within the segment of the character - * given by indexPtr. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -TkTextSegment * -TkTextIndexToSeg(indexPtr, offsetPtr) - TkTextIndex *indexPtr; /* Text index. */ - int *offsetPtr; /* Where to store offset within - * segment, or NULL if offset isn't - * wanted. */ -{ - register TkTextSegment *segPtr; - int offset; - - for (offset = indexPtr->charIndex, segPtr = indexPtr->linePtr->segPtr; - offset >= segPtr->size; - offset -= segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body. */ - } - if (offsetPtr != NULL) { - *offsetPtr = offset; - } - return segPtr; -} - -/* - *-------------------------------------------------------------- - * - * TkTextSegToOffset -- - * - * Given a segment pointer and the line containing it, this - * procedure returns the offset of the segment within its - * line. - * - * Results: - * The return value is the offset (within its line) of the - * first character in segPtr. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextSegToOffset(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment whose offset is desired. */ - TkTextLine *linePtr; /* Line containing segPtr. */ -{ - TkTextSegment *segPtr2; - int offset; - - offset = 0; - for (segPtr2 = linePtr->segPtr; segPtr2 != segPtr; - segPtr2 = segPtr2->nextPtr) { - offset += segPtr2->size; - } - return offset; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextGetIndex -- - * - * Given a string, return the line and character indices that - * it describes. - * - * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the index - * at *indexPtr is filled in; otherwise TCL_ERROR is returned - * and an error message is left in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkTextGetIndex(interp, textPtr, string, indexPtr) - Tcl_Interp *interp; /* Use this for error reporting. */ - TkText *textPtr; /* Information about text widget. */ - char *string; /* Textual description of position. */ - TkTextIndex *indexPtr; /* Index structure to fill in. */ -{ - register char *p; - char *end, *endOfBase; - Tcl_HashEntry *hPtr; - TkTextTag *tagPtr; - TkTextSearch search; - TkTextIndex first, last; - int wantLast, result; - char c; - - /* - *--------------------------------------------------------------------- - * Stage 1: check to see if the index consists of nothing but a mark - * name. We do this check now even though it's also done later, in - * order to allow mark names that include funny characters such as - * spaces or "+1c". - *--------------------------------------------------------------------- - */ - - if (TkTextMarkNameToIndex(textPtr, string, indexPtr) == TCL_OK) { - return TCL_OK; - } - - /* - *------------------------------------------------ - * Stage 2: start again by parsing the base index. - *------------------------------------------------ - */ - - indexPtr->tree = textPtr->tree; - - /* - * First look for the form "tag.first" or "tag.last" where "tag" - * is the name of a valid tag. Try to use up as much as possible - * of the string in this check (strrchr instead of strchr below). - * Doing the check now, and in this way, allows tag names to include - * funny characters like "@" or "+1c". - */ - - p = strrchr(string, '.'); - if (p != NULL) { - if ((p[1] == 'f') && (strncmp(p+1, "first", 5) == 0)) { - wantLast = 0; - endOfBase = p+6; - } else if ((p[1] == 'l') && (strncmp(p+1, "last", 4) == 0)) { - wantLast = 1; - endOfBase = p+5; - } else { - goto tryxy; - } - *p = 0; - hPtr = Tcl_FindHashEntry(&textPtr->tagTable, string); - *p = '.'; - if (hPtr == NULL) { - goto tryxy; - } - tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, - &last); - TkBTreeStartSearch(&first, &last, tagPtr, &search); - if (!TkBTreeCharTagged(&first, tagPtr) && !TkBTreeNextTag(&search)) { - Tcl_AppendResult(interp, - "text doesn't contain any characters tagged with \"", - Tcl_GetHashKey(&textPtr->tagTable, hPtr), "\"", - (char *) NULL); - return TCL_ERROR; - } - *indexPtr = search.curIndex; - if (wantLast) { - while (TkBTreeNextTag(&search)) { - *indexPtr = search.curIndex; - } - } - goto gotBase; - } - - tryxy: - if (string[0] == '@') { - /* - * Find character at a given x,y location in the window. - */ - - int x, y; - - p = string+1; - x = strtol(p, &end, 0); - if ((end == p) || (*end != ',')) { - goto error; - } - p = end+1; - y = strtol(p, &end, 0); - if (end == p) { - goto error; - } - TkTextPixelIndex(textPtr, x, y, indexPtr); - endOfBase = end; - goto gotBase; - } - - if (isdigit(UCHAR(string[0])) || (string[0] == '-')) { - int lineIndex, charIndex; - - /* - * Base is identified with line and character indices. - */ - - lineIndex = strtol(string, &end, 0) - 1; - if ((end == string) || (*end != '.')) { - goto error; - } - p = end+1; - if ((*p == 'e') && (strncmp(p, "end", 3) == 0)) { - charIndex = LAST_CHAR; - endOfBase = p+3; - } else { - charIndex = strtol(p, &end, 0); - if (end == p) { - goto error; - } - endOfBase = end; - } - TkTextMakeIndex(textPtr->tree, lineIndex, charIndex, indexPtr); - goto gotBase; - } - - for (p = string; *p != 0; p++) { - if (isspace(UCHAR(*p)) || (*p == '+') || (*p == '-')) { - break; - } - } - endOfBase = p; - if (string[0] == '.') { - /* - * See if the base position is the name of an embedded window. - */ - - c = *endOfBase; - *endOfBase = 0; - result = TkTextWindowIndex(textPtr, string, indexPtr); - *endOfBase = c; - if (result != 0) { - goto gotBase; - } - } - if ((string[0] == 'e') - && (strncmp(string, "end", (size_t) (endOfBase-string)) == 0)) { - /* - * Base position is end of text. - */ - - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), - 0, indexPtr); - goto gotBase; - } else { - /* - * See if the base position is the name of a mark. - */ - - c = *endOfBase; - *endOfBase = 0; - result = TkTextMarkNameToIndex(textPtr, string, indexPtr); - *endOfBase = c; - if (result == TCL_OK) { - goto gotBase; - } - - /* - * See if the base position is the name of an embedded image - */ - - c = *endOfBase; - *endOfBase = 0; - result = TkTextImageIndex(textPtr, string, indexPtr); - *endOfBase = c; - if (result != 0) { - goto gotBase; - } - } - goto error; - - /* - *------------------------------------------------------------------- - * Stage 3: process zero or more modifiers. Each modifier is either - * a keyword like "wordend" or "linestart", or it has the form - * "op count units" where op is + or -, count is a number, and units - * is "chars" or "lines". - *------------------------------------------------------------------- - */ - - gotBase: - p = endOfBase; - while (1) { - while (isspace(UCHAR(*p))) { - p++; - } - if (*p == 0) { - break; - } - - if ((*p == '+') || (*p == '-')) { - p = ForwBack(p, indexPtr); - } else { - p = StartEnd(p, indexPtr); - } - if (p == NULL) { - goto error; - } - } - return TCL_OK; - - error: - Tcl_AppendResult(interp, "bad text index \"", string, "\"", - (char *) NULL); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextPrintIndex -- - * - * - * This procedure generates a string description of an index, - * suitable for reading in again later. - * - * Results: - * The characters pointed to by string are modified. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkTextPrintIndex(indexPtr, string) - TkTextIndex *indexPtr; /* Pointer to index. */ - char *string; /* Place to store the position. Must have - * at least TK_POS_CHARS characters. */ -{ - sprintf(string, "%d.%d", TkBTreeLineIndex(indexPtr->linePtr) + 1, - indexPtr->charIndex); -} - -/* - *-------------------------------------------------------------- - * - * TkTextIndexCmp -- - * - * Compare two indices to see which one is earlier in - * the text. - * - * Results: - * The return value is 0 if index1Ptr and index2Ptr refer - * to the same position in the file, -1 if index1Ptr refers - * to an earlier position than index2Ptr, and 1 otherwise. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextIndexCmp(index1Ptr, index2Ptr) - TkTextIndex *index1Ptr; /* First index. */ - TkTextIndex *index2Ptr; /* Second index. */ -{ - int line1, line2; - - if (index1Ptr->linePtr == index2Ptr->linePtr) { - if (index1Ptr->charIndex < index2Ptr->charIndex) { - return -1; - } else if (index1Ptr->charIndex > index2Ptr->charIndex) { - return 1; - } else { - return 0; - } - } - line1 = TkBTreeLineIndex(index1Ptr->linePtr); - line2 = TkBTreeLineIndex(index2Ptr->linePtr); - if (line1 < line2) { - return -1; - } - if (line1 > line2) { - return 1; - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * ForwBack -- - * - * This procedure handles +/- modifiers for indices to adjust - * the index forwards or backwards. - * - * Results: - * If the modifier in string is successfully parsed then the - * return value is the address of the first character after the - * modifier, and *indexPtr is updated to reflect the modifier. - * If there is a syntax error in the modifier then NULL is returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static char * -ForwBack(string, indexPtr) - char *string; /* String to parse for additional info - * about modifier (count and units). - * Points to "+" or "-" that starts - * modifier. */ - TkTextIndex *indexPtr; /* Index to update as specified in string. */ -{ - register char *p; - char *end, *units; - int count, lineIndex; - size_t length; - - /* - * Get the count (how many units forward or backward). - */ - - p = string+1; - while (isspace(UCHAR(*p))) { - p++; - } - count = strtol(p, &end, 0); - if (end == p) { - return NULL; - } - p = end; - while (isspace(UCHAR(*p))) { - p++; - } - - /* - * Find the end of this modifier (next space or + or - character), - * then parse the unit specifier and update the position - * accordingly. - */ - - units = p; - while ((*p != 0) && !isspace(UCHAR(*p)) && (*p != '+') && (*p != '-')) { - p++; - } - length = p - units; - if ((*units == 'c') && (strncmp(units, "chars", length) == 0)) { - if (*string == '+') { - TkTextIndexForwChars(indexPtr, count, indexPtr); - } else { - TkTextIndexBackChars(indexPtr, count, indexPtr); - } - } else if ((*units == 'l') && (strncmp(units, "lines", length) == 0)) { - lineIndex = TkBTreeLineIndex(indexPtr->linePtr); - if (*string == '+') { - lineIndex += count; - } else { - lineIndex -= count; - - /* - * The check below retains the character position, even - * if the line runs off the start of the file. Without - * it, the character position will get reset to 0 by - * TkTextMakeIndex. - */ - - if (lineIndex < 0) { - lineIndex = 0; - } - } - TkTextMakeIndex(indexPtr->tree, lineIndex, indexPtr->charIndex, - indexPtr); - } else { - return NULL; - } - return p; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextIndexForwChars -- - * - * Given an index for a text widget, this procedure creates a - * new index that points "count" characters ahead of the source - * index. - * - * Results: - * *dstPtr is modified to refer to the character "count" characters - * after srcPtr, or to the last character in the file if there aren't - * "count" characters left in the file. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkTextIndexForwChars(srcPtr, count, dstPtr) - TkTextIndex *srcPtr; /* Source index. */ - int count; /* How many characters forward to - * move. May be negative. */ - TkTextIndex *dstPtr; /* Destination index: gets modified. */ -{ - TkTextLine *linePtr; - TkTextSegment *segPtr; - int lineLength; - - if (count < 0) { - TkTextIndexBackChars(srcPtr, -count, dstPtr); - return; - } - - *dstPtr = *srcPtr; - dstPtr->charIndex += count; - while (1) { - /* - * Compute the length of the current line. - */ - - lineLength = 0; - for (segPtr = dstPtr->linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - lineLength += segPtr->size; - } - - /* - * If the new index is in the same line then we're done. - * Otherwise go on to the next line. - */ - - if (dstPtr->charIndex < lineLength) { - return; - } - dstPtr->charIndex -= lineLength; - linePtr = TkBTreeNextLine(dstPtr->linePtr); - if (linePtr == NULL) { - dstPtr->charIndex = lineLength - 1; - return; - } - dstPtr->linePtr = linePtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkTextIndexBackChars -- - * - * Given an index for a text widget, this procedure creates a - * new index that points "count" characters earlier than the - * source index. - * - * Results: - * *dstPtr is modified to refer to the character "count" characters - * before srcPtr, or to the first character in the file if there aren't - * "count" characters earlier than srcPtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkTextIndexBackChars(srcPtr, count, dstPtr) - TkTextIndex *srcPtr; /* Source index. */ - int count; /* How many characters backward to - * move. May be negative. */ - TkTextIndex *dstPtr; /* Destination index: gets modified. */ -{ - TkTextSegment *segPtr; - int lineIndex; - - if (count < 0) { - TkTextIndexForwChars(srcPtr, -count, dstPtr); - return; - } - - *dstPtr = *srcPtr; - dstPtr->charIndex -= count; - lineIndex = -1; - while (dstPtr->charIndex < 0) { - /* - * Move back one line in the text. If we run off the beginning - * of the file then just return the first character in the text. - */ - - if (lineIndex < 0) { - lineIndex = TkBTreeLineIndex(dstPtr->linePtr); - } - if (lineIndex == 0) { - dstPtr->charIndex = 0; - return; - } - lineIndex--; - dstPtr->linePtr = TkBTreeFindLine(dstPtr->tree, lineIndex); - - /* - * Compute the length of the line and add that to dstPtr->charIndex. - */ - - for (segPtr = dstPtr->linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - dstPtr->charIndex += segPtr->size; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * StartEnd -- - * - * This procedure handles modifiers like "wordstart" and "lineend" - * to adjust indices forwards or backwards. - * - * Results: - * If the modifier is successfully parsed then the return value - * is the address of the first character after the modifier, and - * *indexPtr is updated to reflect the modifier. If there is a - * syntax error in the modifier then NULL is returned. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static char * -StartEnd(string, indexPtr) - char *string; /* String to parse for additional info - * about modifier (count and units). - * Points to first character of modifer - * word. */ - TkTextIndex *indexPtr; /* Index to mdoify based on string. */ -{ - char *p; - int c, offset; - size_t length; - register TkTextSegment *segPtr; - - /* - * Find the end of the modifier word. - */ - - for (p = string; isalnum(UCHAR(*p)); p++) { - /* Empty loop body. */ - } - length = p-string; - if ((*string == 'l') && (strncmp(string, "lineend", length) == 0) - && (length >= 5)) { - indexPtr->charIndex = 0; - for (segPtr = indexPtr->linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - indexPtr->charIndex += segPtr->size; - } - indexPtr->charIndex -= 1; - } else if ((*string == 'l') && (strncmp(string, "linestart", length) == 0) - && (length >= 5)) { - indexPtr->charIndex = 0; - } else if ((*string == 'w') && (strncmp(string, "wordend", length) == 0) - && (length >= 5)) { - int firstChar = 1; - - /* - * If the current character isn't part of a word then just move - * forward one character. Otherwise move forward until finding - * a character that isn't part of a word and stop there. - */ - - segPtr = TkTextIndexToSeg(indexPtr, &offset); - while (1) { - if (segPtr->typePtr == &tkTextCharType) { - c = segPtr->body.chars[offset]; - if (!isalnum(UCHAR(c)) && (c != '_')) { - break; - } - firstChar = 0; - } - offset += 1; - indexPtr->charIndex += 1; - if (offset >= segPtr->size) { - segPtr = TkTextIndexToSeg(indexPtr, &offset); - } - } - if (firstChar) { - TkTextIndexForwChars(indexPtr, 1, indexPtr); - } - } else if ((*string == 'w') && (strncmp(string, "wordstart", length) == 0) - && (length >= 5)) { - int firstChar = 1; - - /* - * Starting with the current character, look for one that's not - * part of a word and keep moving backward until you find one. - * Then if the character found wasn't the first one, move forward - * again one position. - */ - - segPtr = TkTextIndexToSeg(indexPtr, &offset); - while (1) { - if (segPtr->typePtr == &tkTextCharType) { - c = segPtr->body.chars[offset]; - if (!isalnum(UCHAR(c)) && (c != '_')) { - break; - } - firstChar = 0; - } - offset -= 1; - indexPtr->charIndex -= 1; - if (offset < 0) { - if (indexPtr->charIndex < 0) { - indexPtr->charIndex = 0; - goto done; - } - segPtr = TkTextIndexToSeg(indexPtr, &offset); - } - } - if (!firstChar) { - TkTextIndexForwChars(indexPtr, 1, indexPtr); - } - } else { - return NULL; - } - done: - return p; -} diff --git a/generic/tkTextMark.c b/generic/tkTextMark.c deleted file mode 100644 index 07094f1..0000000 --- a/generic/tkTextMark.c +++ /dev/null @@ -1,775 +0,0 @@ -/* - * tkTextMark.c -- - * - * This file contains the procedure that implement marks for - * text widgets. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextMark.c,v 1.2 1998/09/14 18:23:19 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkText.h" -#include "tkPort.h" - -/* - * Macro that determines the size of a mark segment: - */ - -#define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + sizeof(TkTextMark))) - -/* - * Forward references for procedures defined in this file: - */ - -static void InsertUndisplayProc _ANSI_ARGS_((TkText *textPtr, - TkTextDispChunk *chunkPtr)); -static int MarkDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -static TkTextSegment * MarkCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static void MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static int MarkLayoutProc _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, TkTextSegment *segPtr, - int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, - TkTextDispChunk *chunkPtr)); -static int MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, char *markName)); -static int MarkFindPrev _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, char *markName)); - - -/* - * The following structures declare the "mark" segment types. - * There are actually two types for marks, one with left gravity - * and one with right gravity. They are identical except for - * their gravity property. - */ - -Tk_SegType tkTextRightMarkType = { - "mark", /* name */ - 0, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - MarkDeleteProc, /* deleteProc */ - MarkCleanupProc, /* cleanupProc */ - (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */ - MarkLayoutProc, /* layoutProc */ - MarkCheckProc /* checkProc */ -}; - -Tk_SegType tkTextLeftMarkType = { - "mark", /* name */ - 1, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - MarkDeleteProc, /* deleteProc */ - MarkCleanupProc, /* cleanupProc */ - (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */ - MarkLayoutProc, /* layoutProc */ - MarkCheckProc /* checkProc */ -}; - -/* - *-------------------------------------------------------------- - * - * TkTextMarkCmd -- - * - * This procedure is invoked to process the "mark" options of - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextMarkCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "mark". */ -{ - int c, i; - size_t length; - Tcl_HashEntry *hPtr; - TkTextSegment *markPtr; - Tcl_HashSearch search; - TkTextIndex index; - Tk_SegType *newTypePtr; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[2][0]; - length = strlen(argv[2]); - if ((c == 'g') && (strncmp(argv[2], "gravity", length) == 0)) { - if (argc < 4 || argc > 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark gravity markName ?gravity?\"", - (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[3]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "there is no mark named \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - if (argc == 4) { - if (markPtr->typePtr == &tkTextRightMarkType) { - interp->result = "right"; - } else { - interp->result = "left"; - } - return TCL_OK; - } - length = strlen(argv[4]); - c = argv[4][0]; - if ((c == 'l') && (strncmp(argv[4], "left", length) == 0)) { - newTypePtr = &tkTextLeftMarkType; - } else if ((c == 'r') && (strncmp(argv[4], "right", length) == 0)) { - newTypePtr = &tkTextRightMarkType; - } else { - Tcl_AppendResult(interp, "bad mark gravity \"", - argv[4], "\": must be left or right", (char *) NULL); - return TCL_ERROR; - } - TkTextMarkSegToIndex(textPtr, markPtr, &index); - TkBTreeUnlinkSegment(textPtr->tree, markPtr, - markPtr->body.mark.linePtr); - markPtr->typePtr = newTypePtr; - TkBTreeLinkSegment(markPtr, &index); - } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark names\"", (char *) NULL); - return TCL_ERROR; - } - for (hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, - Tcl_GetHashKey(&textPtr->markTable, hPtr)); - } - } else if ((c == 'n') && (strncmp(argv[2], "next", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark next index\"", (char *) NULL); - return TCL_ERROR; - } - return MarkFindNext(interp, textPtr, argv[3]); - } else if ((c == 'p') && (strncmp(argv[2], "previous", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark previous index\"", (char *) NULL); - return TCL_ERROR; - } - return MarkFindPrev(interp, textPtr, argv[3]); - } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " mark set markName index\"", (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[4], &index) != TCL_OK) { - return TCL_ERROR; - } - TkTextSetMark(textPtr, argv[3], &index); - } else if ((c == 'u') && (strncmp(argv[2], "unset", length) == 0)) { - for (i = 3; i < argc; i++) { - hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[i]); - if (hPtr != NULL) { - markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - if ((markPtr == textPtr->insertMarkPtr) - || (markPtr == textPtr->currentMarkPtr)) { - continue; - } - TkBTreeUnlinkSegment(textPtr->tree, markPtr, - markPtr->body.mark.linePtr); - Tcl_DeleteHashEntry(hPtr); - ckfree((char *) markPtr); - } - } - } else { - Tcl_AppendResult(interp, "bad mark option \"", argv[2], - "\": must be gravity, names, next, previous, set, or unset", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextSetMark -- - * - * Set a mark to a particular position, creating a new mark if - * one doesn't already exist. - * - * Results: - * The return value is a pointer to the mark that was just set. - * - * Side effects: - * A new mark is created, or an existing mark is moved. - * - *---------------------------------------------------------------------- - */ - -TkTextSegment * -TkTextSetMark(textPtr, name, indexPtr) - TkText *textPtr; /* Text widget in which to create mark. */ - char *name; /* Name of mark to set. */ - TkTextIndex *indexPtr; /* Where to set mark. */ -{ - Tcl_HashEntry *hPtr; - TkTextSegment *markPtr; - TkTextIndex insertIndex; - int new; - - hPtr = Tcl_CreateHashEntry(&textPtr->markTable, name, &new); - markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - if (!new) { - /* - * If this is the insertion point that's being moved, be sure - * to force a display update at the old position. Also, don't - * let the insertion cursor be after the final newline of the - * file. - */ - - if (markPtr == textPtr->insertMarkPtr) { - TkTextIndex index, index2; - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextIndexForwChars(&index, 1, &index2); - TkTextChanged(textPtr, &index, &index2); - if (TkBTreeLineIndex(indexPtr->linePtr) - == TkBTreeNumLines(textPtr->tree)) { - TkTextIndexBackChars(indexPtr, 1, &insertIndex); - indexPtr = &insertIndex; - } - } - TkBTreeUnlinkSegment(textPtr->tree, markPtr, - markPtr->body.mark.linePtr); - } else { - markPtr = (TkTextSegment *) ckalloc(MSEG_SIZE); - markPtr->typePtr = &tkTextRightMarkType; - markPtr->size = 0; - markPtr->body.mark.textPtr = textPtr; - markPtr->body.mark.linePtr = indexPtr->linePtr; - markPtr->body.mark.hPtr = hPtr; - Tcl_SetHashValue(hPtr, markPtr); - } - TkBTreeLinkSegment(markPtr, indexPtr); - - /* - * If the mark is the insertion cursor, then update the screen at the - * mark's new location. - */ - - if (markPtr == textPtr->insertMarkPtr) { - TkTextIndex index2; - - TkTextIndexForwChars(indexPtr, 1, &index2); - TkTextChanged(textPtr, indexPtr, &index2); - } - return markPtr; -} - -/* - *-------------------------------------------------------------- - * - * TkTextMarkSegToIndex -- - * - * Given a segment that is a mark, create an index that - * refers to the next text character (or other text segment - * with non-zero size) after the mark. - * - * Results: - * *IndexPtr is filled in with index information. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkTextMarkSegToIndex(textPtr, markPtr, indexPtr) - TkText *textPtr; /* Text widget containing mark. */ - TkTextSegment *markPtr; /* Mark segment. */ - TkTextIndex *indexPtr; /* Index information gets stored here. */ -{ - TkTextSegment *segPtr; - - indexPtr->tree = textPtr->tree; - indexPtr->linePtr = markPtr->body.mark.linePtr; - indexPtr->charIndex = 0; - for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr; - segPtr = segPtr->nextPtr) { - indexPtr->charIndex += segPtr->size; - } -} - -/* - *-------------------------------------------------------------- - * - * TkTextMarkNameToIndex -- - * - * Given the name of a mark, return an index corresponding - * to the mark name. - * - * Results: - * The return value is TCL_OK if "name" exists as a mark in - * the text widget. In this case *indexPtr is filled in with - * the next segment whose after the mark whose size is - * non-zero. TCL_ERROR is returned if the mark doesn't exist - * in the text widget. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextMarkNameToIndex(textPtr, name, indexPtr) - TkText *textPtr; /* Text widget containing mark. */ - char *name; /* Name of mark. */ - TkTextIndex *indexPtr; /* Index information gets stored here. */ -{ - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&textPtr->markTable, name); - if (hPtr == NULL) { - return TCL_ERROR; - } - TkTextMarkSegToIndex(textPtr, (TkTextSegment *) Tcl_GetHashValue(hPtr), - indexPtr); - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * MarkDeleteProc -- - * - * This procedure is invoked by the text B-tree code whenever - * a mark lies in a range of characters being deleted. - * - * Results: - * Returns 1 to indicate that deletion has been rejected. - * - * Side effects: - * None (even if the whole tree is being deleted we don't - * free up the mark; it will be done elsewhere). - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -MarkDeleteProc(segPtr, linePtr, treeGone) - TkTextSegment *segPtr; /* Segment being deleted. */ - TkTextLine *linePtr; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ -{ - return 1; -} - -/* - *-------------------------------------------------------------- - * - * MarkCleanupProc -- - * - * This procedure is invoked by the B-tree code whenever a - * mark segment is moved from one line to another. - * - * Results: - * None. - * - * Side effects: - * The linePtr field of the segment gets updated. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -MarkCleanupProc(markPtr, linePtr) - TkTextSegment *markPtr; /* Mark segment that's being moved. */ - TkTextLine *linePtr; /* Line that now contains segment. */ -{ - markPtr->body.mark.linePtr = linePtr; - return markPtr; -} - -/* - *-------------------------------------------------------------- - * - * MarkLayoutProc -- - * - * This procedure is the "layoutProc" for mark segments. - * - * Results: - * If the mark isn't the insertion cursor then the return - * value is -1 to indicate that this segment shouldn't be - * displayed. If the mark is the insertion character then - * 1 is returned and the chunkPtr structure is filled in. - * - * Side effects: - * None, except for filling in chunkPtr. - * - *-------------------------------------------------------------- - */ - - /*ARGSUSED*/ -static int -MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, - noCharsYet, wrapMode, chunkPtr) - TkText *textPtr; /* Text widget being layed out. */ - TkTextIndex *indexPtr; /* Identifies first character in chunk. */ - TkTextSegment *segPtr; /* Segment corresponding to indexPtr. */ - int offset; /* Offset within segPtr corresponding to - * indexPtr (always 0). */ - int maxX; /* Chunk must not occupy pixels at this - * position or higher. */ - int maxChars; /* Chunk must not include more than this - * many characters. */ - int noCharsYet; /* Non-zero means no characters have been - * assigned to this line yet. */ - Tk_Uid wrapMode; /* Not used. */ - register TkTextDispChunk *chunkPtr; - /* Structure to fill in with information - * about this chunk. The x field has already - * been set by the caller. */ -{ - if (segPtr != textPtr->insertMarkPtr) { - return -1; - } - - chunkPtr->displayProc = TkTextInsertDisplayProc; - chunkPtr->undisplayProc = InsertUndisplayProc; - chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; - chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL; - chunkPtr->numChars = 0; - chunkPtr->minAscent = 0; - chunkPtr->minDescent = 0; - chunkPtr->minHeight = 0; - chunkPtr->width = 0; - - /* - * Note: can't break a line after the insertion cursor: this - * prevents the insertion cursor from being stranded at the end - * of a line. - */ - - chunkPtr->breakIndex = -1; - chunkPtr->clientData = (ClientData) textPtr; - return 1; -} - -/* - *-------------------------------------------------------------- - * - * TkTextInsertDisplayProc -- - * - * This procedure is called to display the insertion - * cursor. - * - * Results: - * None. - * - * Side effects: - * Graphics are drawn. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkTextInsertDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) - TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */ - int x; /* X-position in dst at which to - * draw this chunk (may differ from - * the x-position in the chunk because - * of scrolling). */ - int y; /* Y-position at which to draw this - * chunk in dst (x-position is in - * the chunk itself). */ - int height; /* Total height of line. */ - int baseline; /* Offset of baseline from y. */ - Display *display; /* Display to use for drawing. */ - Drawable dst; /* Pixmap or window in which to draw - * chunk. */ - int screenY; /* Y-coordinate in text window that - * corresponds to y. */ -{ - TkText *textPtr = (TkText *) chunkPtr->clientData; - int halfWidth = textPtr->insertWidth/2; - - if ((x + halfWidth) < 0) { - /* - * The insertion cursor is off-screen. Just return. - */ - - return; - } - - /* - * As a special hack to keep the cursor visible on mono displays - * (or anywhere else that the selection and insertion cursors - * have the same color) write the default background in the cursor - * area (instead of nothing) when the cursor isn't on. Otherwise - * the selection might hide the cursor. - */ - - if (textPtr->flags & INSERT_ON) { - Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder, - x - textPtr->insertWidth/2, y, textPtr->insertWidth, - height, textPtr->insertBorderWidth, TK_RELIEF_RAISED); - } else if (textPtr->selBorder == textPtr->insertBorder) { - Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border, - x - textPtr->insertWidth/2, y, textPtr->insertWidth, - height, 0, TK_RELIEF_FLAT); - } -} - -/* - *-------------------------------------------------------------- - * - * InsertUndisplayProc -- - * - * This procedure is called when the insertion cursor is no - * longer at a visible point on the display. It does nothing - * right now. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -InsertUndisplayProc(textPtr, chunkPtr) - TkText *textPtr; /* Overall information about text - * widget. */ - TkTextDispChunk *chunkPtr; /* Chunk that is about to be freed. */ -{ - return; -} - -/* - *-------------------------------------------------------------- - * - * MarkCheckProc -- - * - * This procedure is invoked by the B-tree code to perform - * consistency checks on mark segments. - * - * Results: - * None. - * - * Side effects: - * The procedure panics if it detects anything wrong with - * the mark. - * - *-------------------------------------------------------------- - */ - -static void -MarkCheckProc(markPtr, linePtr) - TkTextSegment *markPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ -{ - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - - if (markPtr->body.mark.linePtr != linePtr) { - panic("MarkCheckProc: markPtr->body.mark.linePtr bogus"); - } - - /* - * Make sure that the mark is still present in the text's mark - * hash table. - */ - - for (hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.textPtr->markTable, - &search); hPtr != markPtr->body.mark.hPtr; - hPtr = Tcl_NextHashEntry(&search)) { - if (hPtr == NULL) { - panic("MarkCheckProc couldn't find hash table entry for mark"); - } - } -} - -/* - *-------------------------------------------------------------- - * - * MarkFindNext -- - * - * This procedure searches forward for the next mark. - * - * Results: - * A standard Tcl result, which is a mark name or an empty string. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -MarkFindNext(interp, textPtr, string) - Tcl_Interp *interp; /* For error reporting */ - TkText *textPtr; /* The widget */ - char *string; /* The starting index or mark name */ -{ - TkTextIndex index; - Tcl_HashEntry *hPtr; - register TkTextSegment *segPtr; - int offset; - - - hPtr = Tcl_FindHashEntry(&textPtr->markTable, string); - if (hPtr != NULL) { - /* - * If given a mark name, return the next mark in the list of - * segments, even if it happens to be at the same character position. - */ - segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - TkTextMarkSegToIndex(textPtr, segPtr, &index); - segPtr = segPtr->nextPtr; - } else { - /* - * For non-mark name indices we want to return any marks that - * are right at the index. - */ - if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) { - return TCL_ERROR; - } - for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.charIndex; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body */ ; - } - } - while (1) { - /* - * segPtr points at the first possible candidate, - * or NULL if we ran off the end of the line. - */ - for ( ; segPtr != NULL ; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr == &tkTextRightMarkType || - segPtr->typePtr == &tkTextLeftMarkType) { - Tcl_SetResult(interp, - Tcl_GetHashKey(&textPtr->markTable, segPtr->body.mark.hPtr), - TCL_STATIC); - return TCL_OK; - } - } - index.linePtr = TkBTreeNextLine(index.linePtr); - if (index.linePtr == (TkTextLine *) NULL) { - return TCL_OK; - } - index.charIndex = 0; - segPtr = index.linePtr->segPtr; - } -} - -/* - *-------------------------------------------------------------- - * - * MarkFindPrev -- - * - * This procedure searches backwards for the previous mark. - * - * Results: - * A standard Tcl result, which is a mark name or an empty string. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -MarkFindPrev(interp, textPtr, string) - Tcl_Interp *interp; /* For error reporting */ - TkText *textPtr; /* The widget */ - char *string; /* The starting index or mark name */ -{ - TkTextIndex index; - Tcl_HashEntry *hPtr; - register TkTextSegment *segPtr, *seg2Ptr, *prevPtr; - int offset; - - - hPtr = Tcl_FindHashEntry(&textPtr->markTable, string); - if (hPtr != NULL) { - /* - * If given a mark name, return the previous mark in the list of - * segments, even if it happens to be at the same character position. - */ - segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - TkTextMarkSegToIndex(textPtr, segPtr, &index); - } else { - /* - * For non-mark name indices we do not return any marks that - * are right at the index. - */ - if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) { - return TCL_ERROR; - } - for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.charIndex; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body */ ; - } - } - while (1) { - /* - * segPtr points just past the first possible candidate, - * or at the begining of the line. - */ - for (prevPtr = NULL, seg2Ptr = index.linePtr->segPtr; - seg2Ptr != NULL && seg2Ptr != segPtr; - seg2Ptr = seg2Ptr->nextPtr) { - if (seg2Ptr->typePtr == &tkTextRightMarkType || - seg2Ptr->typePtr == &tkTextLeftMarkType) { - prevPtr = seg2Ptr; - } - } - if (prevPtr != NULL) { - Tcl_SetResult(interp, - Tcl_GetHashKey(&textPtr->markTable, prevPtr->body.mark.hPtr), - TCL_STATIC); - return TCL_OK; - } - index.linePtr = TkBTreePreviousLine(index.linePtr); - if (index.linePtr == (TkTextLine *) NULL) { - return TCL_OK; - } - segPtr = NULL; - } -} diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c deleted file mode 100644 index c3e1c5d..0000000 --- a/generic/tkTextTag.c +++ /dev/null @@ -1,1376 +0,0 @@ -/* - * tkTextTag.c -- - * - * This module implements the "tag" subcommand of the widget command - * for text widgets, plus most of the other high-level functions - * related to tags. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextTag.c,v 1.2 1998/09/14 18:23:19 stanton Exp $ - */ - -#include "default.h" -#include "tkPort.h" -#include "tk.h" -#include "tkText.h" - -/* - * Information used for parsing tag configuration information: - */ - -static Tk_ConfigSpec tagConfigSpecs[] = { - {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, border), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-bgstipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, bgStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-borderwidth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextTag, bdString), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-fgstipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, fgStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, tkfont), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, fgColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-justify", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, justifyString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-lmargin1", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, lMargin1String), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-lmargin2", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, lMargin2String), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-offset", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, offsetString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-overstrike", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, overstrikeString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-relief", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, reliefString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-rmargin", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, rMarginString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-spacing1", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, spacing1String), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-spacing2", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, spacing2String), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-spacing3", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, spacing3String), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-tabs", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, tabString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-underline", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, underlineString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-wrap", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextTag, wrapMode), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - * Forward declarations for procedures defined later in this file: - */ - -static void ChangeTagPriority _ANSI_ARGS_((TkText *textPtr, - TkTextTag *tagPtr, int prio)); -static TkTextTag * FindTag _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, char *tagName)); -static void SortTags _ANSI_ARGS_((int numTags, - TkTextTag **tagArrayPtr)); -static int TagSortProc _ANSI_ARGS_((CONST VOID *first, - CONST VOID *second)); - -/* - *-------------------------------------------------------------- - * - * TkTextTagCmd -- - * - * This procedure is invoked to process the "tag" options of - * the widget command for text widgets. See the user documentation - * for details on what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextTagCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "tag". */ -{ - int c, i, addTag; - size_t length; - char *fullOption; - register TkTextTag *tagPtr; - TkTextIndex first, last, index1, index2; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[2][0]; - length = strlen(argv[2]); - if ((c == 'a') && (strncmp(argv[2], "add", length) == 0)) { - fullOption = "add"; - addTag = 1; - - addAndRemove: - if (argc < 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag ", fullOption, - " tagName index1 ?index2 index1 index2 ...?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = TkTextCreateTag(textPtr, argv[3]); - for (i = 4; i < argc; i += 2) { - if (TkTextGetIndex(interp, textPtr, argv[i], &index1) != TCL_OK) { - return TCL_ERROR; - } - if (argc > (i+1)) { - if (TkTextGetIndex(interp, textPtr, argv[i+1], &index2) - != TCL_OK) { - return TCL_ERROR; - } - if (TkTextIndexCmp(&index1, &index2) >= 0) { - return TCL_OK; - } - } else { - index2 = index1; - TkTextIndexForwChars(&index2, 1, &index2); - } - - if (tagPtr->affectsDisplay) { - TkTextRedrawTag(textPtr, &index1, &index2, tagPtr, !addTag); - } else { - /* - * Still need to trigger enter/leave events on tags that - * have changed. - */ - - TkTextEventuallyRepick(textPtr); - } - TkBTreeTag(&index1, &index2, tagPtr, addTag); - - /* - * If the tag is "sel" then grab the selection if we're supposed - * to export it and don't already have it. Also, invalidate - * partially-completed selection retrievals. - */ - - if (tagPtr == textPtr->selTagPtr) { - if (addTag && textPtr->exportSelection - && !(textPtr->flags & GOT_SELECTION)) { - Tk_OwnSelection(textPtr->tkwin, XA_PRIMARY, - TkTextLostSelection, (ClientData) textPtr); - textPtr->flags |= GOT_SELECTION; - } - textPtr->abortSelections = 1; - } - } - } else if ((c == 'b') && (strncmp(argv[2], "bind", length) == 0)) { - if ((argc < 4) || (argc > 6)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag bind tagName ?sequence? ?command?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = TkTextCreateTag(textPtr, argv[3]); - - /* - * Make a binding table if the widget doesn't already have - * one. - */ - - if (textPtr->bindingTable == NULL) { - textPtr->bindingTable = Tk_CreateBindingTable(interp); - } - - if (argc == 6) { - int append = 0; - unsigned long mask; - - if (argv[5][0] == 0) { - return Tk_DeleteBinding(interp, textPtr->bindingTable, - (ClientData) tagPtr, argv[4]); - } - if (argv[5][0] == '+') { - argv[5]++; - append = 1; - } - mask = Tk_CreateBinding(interp, textPtr->bindingTable, - (ClientData) tagPtr, argv[4], argv[5], append); - if (mask == 0) { - return TCL_ERROR; - } - if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask - |Button2MotionMask|Button3MotionMask|Button4MotionMask - |Button5MotionMask|ButtonPressMask|ButtonReleaseMask - |EnterWindowMask|LeaveWindowMask|KeyPressMask - |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { - Tk_DeleteBinding(interp, textPtr->bindingTable, - (ClientData) tagPtr, argv[4]); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "requested illegal events; ", - "only key, button, motion, enter, leave, and virtual ", - "events may be used", (char *) NULL); - return TCL_ERROR; - } - } else if (argc == 5) { - char *command; - - command = Tk_GetBinding(interp, textPtr->bindingTable, - (ClientData) tagPtr, argv[4]); - if (command == NULL) { - return TCL_ERROR; - } - interp->result = command; - } else { - Tk_GetAllBindings(interp, textPtr->bindingTable, - (ClientData) tagPtr); - } - } else if ((c == 'c') && (strncmp(argv[2], "cget", length) == 0) - && (length >= 2)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag cget tagName option\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag(interp, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_ERROR; - } - return Tk_ConfigureValue(interp, textPtr->tkwin, tagConfigSpecs, - (char *) tagPtr, argv[4], 0); - } else if ((c == 'c') && (strncmp(argv[2], "configure", length) == 0) - && (length >= 2)) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag configure tagName ?option? ?value? ", - "?option value ...?\"", (char *) NULL); - return TCL_ERROR; - } - tagPtr = TkTextCreateTag(textPtr, argv[3]); - if (argc == 4) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs, - (char *) tagPtr, (char *) NULL, 0); - } else if (argc == 5) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, tagConfigSpecs, - (char *) tagPtr, argv[4], 0); - } else { - int result; - - result = Tk_ConfigureWidget(interp, textPtr->tkwin, tagConfigSpecs, - argc-4, argv+4, (char *) tagPtr, 0); - /* - * Some of the configuration options, like -underline - * and -justify, require additional translation (this is - * needed because we need to distinguish a particular value - * of an option from "unspecified"). - */ - - if (tagPtr->bdString != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->bdString, - &tagPtr->borderWidth) != TCL_OK) { - return TCL_ERROR; - } - if (tagPtr->borderWidth < 0) { - tagPtr->borderWidth = 0; - } - } - if (tagPtr->reliefString != NULL) { - if (Tk_GetRelief(interp, tagPtr->reliefString, - &tagPtr->relief) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->justifyString != NULL) { - if (Tk_GetJustify(interp, tagPtr->justifyString, - &tagPtr->justify) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->lMargin1String != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->lMargin1String, &tagPtr->lMargin1) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->lMargin2String != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->lMargin2String, &tagPtr->lMargin2) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->offsetString != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, tagPtr->offsetString, - &tagPtr->offset) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->overstrikeString != NULL) { - if (Tcl_GetBoolean(interp, tagPtr->overstrikeString, - &tagPtr->overstrike) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->rMarginString != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->rMarginString, &tagPtr->rMargin) != TCL_OK) { - return TCL_ERROR; - } - } - if (tagPtr->spacing1String != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->spacing1String, &tagPtr->spacing1) != TCL_OK) { - return TCL_ERROR; - } - if (tagPtr->spacing1 < 0) { - tagPtr->spacing1 = 0; - } - } - if (tagPtr->spacing2String != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->spacing2String, &tagPtr->spacing2) != TCL_OK) { - return TCL_ERROR; - } - if (tagPtr->spacing2 < 0) { - tagPtr->spacing2 = 0; - } - } - if (tagPtr->spacing3String != NULL) { - if (Tk_GetPixels(interp, textPtr->tkwin, - tagPtr->spacing3String, &tagPtr->spacing3) != TCL_OK) { - return TCL_ERROR; - } - if (tagPtr->spacing3 < 0) { - tagPtr->spacing3 = 0; - } - } - if (tagPtr->tabArrayPtr != NULL) { - ckfree((char *) tagPtr->tabArrayPtr); - tagPtr->tabArrayPtr = NULL; - } - if (tagPtr->tabString != NULL) { - tagPtr->tabArrayPtr = TkTextGetTabs(interp, textPtr->tkwin, - tagPtr->tabString); - if (tagPtr->tabArrayPtr == NULL) { - return TCL_ERROR; - } - } - if (tagPtr->underlineString != NULL) { - if (Tcl_GetBoolean(interp, tagPtr->underlineString, - &tagPtr->underline) != TCL_OK) { - return TCL_ERROR; - } - } - if ((tagPtr->wrapMode != NULL) - && (tagPtr->wrapMode != tkTextCharUid) - && (tagPtr->wrapMode != tkTextNoneUid) - && (tagPtr->wrapMode != tkTextWordUid)) { - Tcl_AppendResult(interp, "bad wrap mode \"", tagPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - tagPtr->wrapMode = NULL; - return TCL_ERROR; - } - - /* - * If the "sel" tag was changed, be sure to mirror information - * from the tag back into the text widget record. NOTE: we - * don't have to free up information in the widget record - * before overwriting it, because it was mirrored in the tag - * and hence freed when the tag field was overwritten. - */ - - if (tagPtr == textPtr->selTagPtr) { - textPtr->selBorder = tagPtr->border; - textPtr->selBdString = tagPtr->bdString; - textPtr->selFgColorPtr = tagPtr->fgColor; - } - tagPtr->affectsDisplay = 0; - if ((tagPtr->border != NULL) - || (tagPtr->bdString != NULL) - || (tagPtr->reliefString != NULL) - || (tagPtr->bgStipple != None) - || (tagPtr->fgColor != NULL) || (tagPtr->tkfont != None) - || (tagPtr->fgStipple != None) - || (tagPtr->justifyString != NULL) - || (tagPtr->lMargin1String != NULL) - || (tagPtr->lMargin2String != NULL) - || (tagPtr->offsetString != NULL) - || (tagPtr->overstrikeString != NULL) - || (tagPtr->rMarginString != NULL) - || (tagPtr->spacing1String != NULL) - || (tagPtr->spacing2String != NULL) - || (tagPtr->spacing3String != NULL) - || (tagPtr->tabString != NULL) - || (tagPtr->underlineString != NULL) - || (tagPtr->wrapMode != NULL)) { - tagPtr->affectsDisplay = 1; - } - TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, - (TkTextIndex *) NULL, tagPtr, 1); - return result; - } - } else if ((c == 'd') && (strncmp(argv[2], "delete", length) == 0)) { - Tcl_HashEntry *hPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag delete tagName tagName ...\"", - (char *) NULL); - return TCL_ERROR; - } - for (i = 3; i < argc; i++) { - hPtr = Tcl_FindHashEntry(&textPtr->tagTable, argv[i]); - if (hPtr == NULL) { - continue; - } - tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); - if (tagPtr == textPtr->selTagPtr) { - continue; - } - if (tagPtr->affectsDisplay) { - TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, - (TkTextIndex *) NULL, tagPtr, 1); - } - TkBTreeTag(TkTextMakeIndex(textPtr->tree, 0, 0, &first), - TkTextMakeIndex(textPtr->tree, - TkBTreeNumLines(textPtr->tree), 0, &last), - tagPtr, 0); - Tcl_DeleteHashEntry(hPtr); - if (textPtr->bindingTable != NULL) { - Tk_DeleteAllBindings(textPtr->bindingTable, - (ClientData) tagPtr); - } - - /* - * Update the tag priorities to reflect the deletion of this tag. - */ - - ChangeTagPriority(textPtr, tagPtr, textPtr->numTags-1); - textPtr->numTags -= 1; - TkTextFreeTag(textPtr, tagPtr); - } - } else if ((c == 'l') && (strncmp(argv[2], "lower", length) == 0)) { - TkTextTag *tagPtr2; - int prio; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag lower tagName ?belowThis?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag(interp, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_ERROR; - } - if (argc == 5) { - tagPtr2 = FindTag(interp, textPtr, argv[4]); - if (tagPtr2 == NULL) { - return TCL_ERROR; - } - if (tagPtr->priority < tagPtr2->priority) { - prio = tagPtr2->priority - 1; - } else { - prio = tagPtr2->priority; - } - } else { - prio = 0; - } - ChangeTagPriority(textPtr, tagPtr, prio); - TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, - tagPtr, 1); - } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0) - && (length >= 2)) { - TkTextTag **arrayPtr; - int arraySize; - - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag names ?index?\"", - (char *) NULL); - return TCL_ERROR; - } - if (argc == 3) { - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - - arrayPtr = (TkTextTag **) ckalloc((unsigned) - (textPtr->numTags * sizeof(TkTextTag *))); - for (i = 0, hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search); - hPtr != NULL; i++, hPtr = Tcl_NextHashEntry(&search)) { - arrayPtr[i] = (TkTextTag *) Tcl_GetHashValue(hPtr); - } - arraySize = textPtr->numTags; - } else { - if (TkTextGetIndex(interp, textPtr, argv[3], &index1) - != TCL_OK) { - return TCL_ERROR; - } - arrayPtr = TkBTreeGetTags(&index1, &arraySize); - if (arrayPtr == NULL) { - return TCL_OK; - } - } - SortTags(arraySize, arrayPtr); - for (i = 0; i < arraySize; i++) { - tagPtr = arrayPtr[i]; - Tcl_AppendElement(interp, tagPtr->name); - } - ckfree((char *) arrayPtr); - } else if ((c == 'n') && (strncmp(argv[2], "nextrange", length) == 0) - && (length >= 2)) { - TkTextSearch tSearch; - char position[TK_POS_CHARS]; - - if ((argc != 5) && (argc != 6)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag nextrange tagName index1 ?index2?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_OK; - } - if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) { - return TCL_ERROR; - } - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), - 0, &last); - if (argc == 5) { - index2 = last; - } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2) - != TCL_OK) { - return TCL_ERROR; - } - - /* - * The search below is a bit tricky. Rather than use the B-tree - * facilities to stop the search at index2, let it search up - * until the end of the file but check for a position past index2 - * ourselves. The reason for doing it this way is that we only - * care whether the *start* of the range is before index2; once - * we find the start, we don't want TkBTreeNextTag to abort the - * search because the end of the range is after index2. - */ - - TkBTreeStartSearch(&index1, &last, tagPtr, &tSearch); - if (TkBTreeCharTagged(&index1, tagPtr)) { - TkTextSegment *segPtr; - int offset; - - /* - * The first character is tagged. See if there is an - * on-toggle just before the character. If not, then - * skip to the end of this tagged range. - */ - - for (segPtr = index1.linePtr->segPtr, offset = index1.charIndex; - offset >= 0; - offset -= segPtr->size, segPtr = segPtr->nextPtr) { - if ((offset == 0) && (segPtr->typePtr == &tkTextToggleOnType) - && (segPtr->body.toggle.tagPtr == tagPtr)) { - goto gotStart; - } - } - if (!TkBTreeNextTag(&tSearch)) { - return TCL_OK; - } - } - - /* - * Find the start of the tagged range. - */ - - if (!TkBTreeNextTag(&tSearch)) { - return TCL_OK; - } - gotStart: - if (TkTextIndexCmp(&tSearch.curIndex, &index2) >= 0) { - return TCL_OK; - } - TkTextPrintIndex(&tSearch.curIndex, position); - Tcl_AppendElement(interp, position); - TkBTreeNextTag(&tSearch); - TkTextPrintIndex(&tSearch.curIndex, position); - Tcl_AppendElement(interp, position); - } else if ((c == 'p') && (strncmp(argv[2], "prevrange", length) == 0) - && (length >= 2)) { - TkTextSearch tSearch; - char position1[TK_POS_CHARS]; - char position2[TK_POS_CHARS]; - - if ((argc != 5) && (argc != 6)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag prevrange tagName index1 ?index2?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_OK; - } - if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) { - return TCL_ERROR; - } - if (argc == 5) { - TkTextMakeIndex(textPtr->tree, 0, 0, &index2); - } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2) - != TCL_OK) { - return TCL_ERROR; - } - - /* - * The search below is a bit weird. The previous toggle can be - * either an on or off toggle. If it is an on toggle, then we - * need to turn around and search forward for the end toggle. - * Otherwise we keep searching backwards. - */ - - TkBTreeStartSearchBack(&index1, &index2, tagPtr, &tSearch); - - if (!TkBTreePrevTag(&tSearch)) { - return TCL_OK; - } - if (tSearch.segPtr->typePtr == &tkTextToggleOnType) { - TkTextPrintIndex(&tSearch.curIndex, position1); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), - 0, &last); - TkBTreeStartSearch(&tSearch.curIndex, &last, tagPtr, &tSearch); - TkBTreeNextTag(&tSearch); - TkTextPrintIndex(&tSearch.curIndex, position2); - } else { - TkTextPrintIndex(&tSearch.curIndex, position2); - TkBTreePrevTag(&tSearch); - if (TkTextIndexCmp(&tSearch.curIndex, &index2) < 0) { - return TCL_OK; - } - TkTextPrintIndex(&tSearch.curIndex, position1); - } - Tcl_AppendElement(interp, position1); - Tcl_AppendElement(interp, position2); - } else if ((c == 'r') && (strncmp(argv[2], "raise", length) == 0) - && (length >= 3)) { - TkTextTag *tagPtr2; - int prio; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag raise tagName ?aboveThis?\"", - (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag(interp, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_ERROR; - } - if (argc == 5) { - tagPtr2 = FindTag(interp, textPtr, argv[4]); - if (tagPtr2 == NULL) { - return TCL_ERROR; - } - if (tagPtr->priority <= tagPtr2->priority) { - prio = tagPtr2->priority; - } else { - prio = tagPtr2->priority + 1; - } - } else { - prio = textPtr->numTags-1; - } - ChangeTagPriority(textPtr, tagPtr, prio); - TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, - tagPtr, 1); - } else if ((c == 'r') && (strncmp(argv[2], "ranges", length) == 0) - && (length >= 3)) { - TkTextSearch tSearch; - char position[TK_POS_CHARS]; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " tag ranges tagName\"", (char *) NULL); - return TCL_ERROR; - } - tagPtr = FindTag((Tcl_Interp *) NULL, textPtr, argv[3]); - if (tagPtr == NULL) { - return TCL_OK; - } - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), - 0, &last); - TkBTreeStartSearch(&first, &last, tagPtr, &tSearch); - if (TkBTreeCharTagged(&first, tagPtr)) { - TkTextPrintIndex(&first, position); - Tcl_AppendElement(interp, position); - } - while (TkBTreeNextTag(&tSearch)) { - TkTextPrintIndex(&tSearch.curIndex, position); - Tcl_AppendElement(interp, position); - } - } else if ((c == 'r') && (strncmp(argv[2], "remove", length) == 0) - && (length >= 2)) { - fullOption = "remove"; - addTag = 0; - goto addAndRemove; - } else { - Tcl_AppendResult(interp, "bad tag option \"", argv[2], - "\": must be add, bind, cget, configure, delete, lower, ", - "names, nextrange, raise, ranges, or remove", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextCreateTag -- - * - * Find the record describing a tag within a given text widget, - * creating a new record if one doesn't already exist. - * - * Results: - * The return value is a pointer to the TkTextTag record for tagName. - * - * Side effects: - * A new tag record is created if there isn't one already defined - * for tagName. - * - *---------------------------------------------------------------------- - */ - -TkTextTag * -TkTextCreateTag(textPtr, tagName) - TkText *textPtr; /* Widget in which tag is being used. */ - char *tagName; /* Name of desired tag. */ -{ - register TkTextTag *tagPtr; - Tcl_HashEntry *hPtr; - int new; - - hPtr = Tcl_CreateHashEntry(&textPtr->tagTable, tagName, &new); - if (!new) { - return (TkTextTag *) Tcl_GetHashValue(hPtr); - } - - /* - * No existing entry. Create a new one, initialize it, and add a - * pointer to it to the hash table entry. - */ - - tagPtr = (TkTextTag *) ckalloc(sizeof(TkTextTag)); - tagPtr->name = Tcl_GetHashKey(&textPtr->tagTable, hPtr); - tagPtr->toggleCount = 0; - tagPtr->tagRootPtr = NULL; - tagPtr->priority = textPtr->numTags; - tagPtr->border = NULL; - tagPtr->bdString = NULL; - tagPtr->borderWidth = 0; - tagPtr->reliefString = NULL; - tagPtr->relief = TK_RELIEF_FLAT; - tagPtr->bgStipple = None; - tagPtr->fgColor = NULL; - tagPtr->tkfont = NULL; - tagPtr->fgStipple = None; - tagPtr->justifyString = NULL; - tagPtr->justify = TK_JUSTIFY_LEFT; - tagPtr->lMargin1String = NULL; - tagPtr->lMargin1 = 0; - tagPtr->lMargin2String = NULL; - tagPtr->lMargin2 = 0; - tagPtr->offsetString = NULL; - tagPtr->offset = 0; - tagPtr->overstrikeString = NULL; - tagPtr->overstrike = 0; - tagPtr->rMarginString = NULL; - tagPtr->rMargin = 0; - tagPtr->spacing1String = NULL; - tagPtr->spacing1 = 0; - tagPtr->spacing2String = NULL; - tagPtr->spacing2 = 0; - tagPtr->spacing3String = NULL; - tagPtr->spacing3 = 0; - tagPtr->tabString = NULL; - tagPtr->tabArrayPtr = NULL; - tagPtr->underlineString = NULL; - tagPtr->underline = 0; - tagPtr->wrapMode = NULL; - tagPtr->affectsDisplay = 0; - textPtr->numTags++; - Tcl_SetHashValue(hPtr, tagPtr); - return tagPtr; -} - -/* - *---------------------------------------------------------------------- - * - * FindTag -- - * - * See if tag is defined for a given widget. - * - * Results: - * If tagName is defined in textPtr, a pointer to its TkTextTag - * structure is returned. Otherwise NULL is returned and an - * error message is recorded in interp->result unless interp - * is NULL. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static TkTextTag * -FindTag(interp, textPtr, tagName) - Tcl_Interp *interp; /* Interpreter to use for error message; - * if NULL, then don't record an error - * message. */ - TkText *textPtr; /* Widget in which tag is being used. */ - char *tagName; /* Name of desired tag. */ -{ - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&textPtr->tagTable, tagName); - if (hPtr != NULL) { - return (TkTextTag *) Tcl_GetHashValue(hPtr); - } - if (interp != NULL) { - Tcl_AppendResult(interp, "tag \"", tagName, - "\" isn't defined in text widget", (char *) NULL); - } - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextFreeTag -- - * - * This procedure is called when a tag is deleted to free up the - * memory and other resources associated with the tag. - * - * Results: - * None. - * - * Side effects: - * Memory and other resources are freed. - * - *---------------------------------------------------------------------- - */ - -void -TkTextFreeTag(textPtr, tagPtr) - TkText *textPtr; /* Info about overall widget. */ - register TkTextTag *tagPtr; /* Tag being deleted. */ -{ - if (tagPtr->border != None) { - Tk_Free3DBorder(tagPtr->border); - } - if (tagPtr->bdString != NULL) { - ckfree(tagPtr->bdString); - } - if (tagPtr->reliefString != NULL) { - ckfree(tagPtr->reliefString); - } - if (tagPtr->bgStipple != None) { - Tk_FreeBitmap(textPtr->display, tagPtr->bgStipple); - } - if (tagPtr->fgColor != None) { - Tk_FreeColor(tagPtr->fgColor); - } - Tk_FreeFont(tagPtr->tkfont); - if (tagPtr->fgStipple != None) { - Tk_FreeBitmap(textPtr->display, tagPtr->fgStipple); - } - if (tagPtr->justifyString != NULL) { - ckfree(tagPtr->justifyString); - } - if (tagPtr->lMargin1String != NULL) { - ckfree(tagPtr->lMargin1String); - } - if (tagPtr->lMargin2String != NULL) { - ckfree(tagPtr->lMargin2String); - } - if (tagPtr->offsetString != NULL) { - ckfree(tagPtr->offsetString); - } - if (tagPtr->overstrikeString != NULL) { - ckfree(tagPtr->overstrikeString); - } - if (tagPtr->rMarginString != NULL) { - ckfree(tagPtr->rMarginString); - } - if (tagPtr->spacing1String != NULL) { - ckfree(tagPtr->spacing1String); - } - if (tagPtr->spacing2String != NULL) { - ckfree(tagPtr->spacing2String); - } - if (tagPtr->spacing3String != NULL) { - ckfree(tagPtr->spacing3String); - } - if (tagPtr->tabString != NULL) { - ckfree(tagPtr->tabString); - } - if (tagPtr->tabArrayPtr != NULL) { - ckfree((char *) tagPtr->tabArrayPtr); - } - if (tagPtr->underlineString != NULL) { - ckfree(tagPtr->underlineString); - } - ckfree((char *) tagPtr); -} - -/* - *---------------------------------------------------------------------- - * - * SortTags -- - * - * This procedure sorts an array of tag pointers in increasing - * order of priority, optimizing for the common case where the - * array is small. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -SortTags(numTags, tagArrayPtr) - int numTags; /* Number of tag pointers at *tagArrayPtr. */ - TkTextTag **tagArrayPtr; /* Pointer to array of pointers. */ -{ - int i, j, prio; - register TkTextTag **tagPtrPtr; - TkTextTag **maxPtrPtr, *tmp; - - if (numTags < 2) { - return; - } - if (numTags < 20) { - for (i = numTags-1; i > 0; i--, tagArrayPtr++) { - maxPtrPtr = tagPtrPtr = tagArrayPtr; - prio = tagPtrPtr[0]->priority; - for (j = i, tagPtrPtr++; j > 0; j--, tagPtrPtr++) { - if (tagPtrPtr[0]->priority < prio) { - prio = tagPtrPtr[0]->priority; - maxPtrPtr = tagPtrPtr; - } - } - tmp = *maxPtrPtr; - *maxPtrPtr = *tagArrayPtr; - *tagArrayPtr = tmp; - } - } else { - qsort((VOID *) tagArrayPtr, (unsigned) numTags, sizeof (TkTextTag *), - TagSortProc); - } -} - -/* - *---------------------------------------------------------------------- - * - * TagSortProc -- - * - * This procedure is called by qsort when sorting an array of - * tags in priority order. - * - * Results: - * The return value is -1 if the first argument should be before - * the second element (i.e. it has lower priority), 0 if it's - * equivalent (this should never happen!), and 1 if it should be - * after the second element. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -TagSortProc(first, second) - CONST VOID *first, *second; /* Elements to be compared. */ -{ - TkTextTag *tagPtr1, *tagPtr2; - - tagPtr1 = * (TkTextTag **) first; - tagPtr2 = * (TkTextTag **) second; - return tagPtr1->priority - tagPtr2->priority; -} - -/* - *---------------------------------------------------------------------- - * - * ChangeTagPriority -- - * - * This procedure changes the priority of a tag by modifying - * its priority and the priorities of other tags that are affected - * by the change. - * - * Results: - * None. - * - * Side effects: - * Priorities may be changed for some or all of the tags in - * textPtr. The tags will be arranged so that there is exactly - * one tag at each priority level between 0 and textPtr->numTags-1, - * with tagPtr at priority "prio". - * - *---------------------------------------------------------------------- - */ - -static void -ChangeTagPriority(textPtr, tagPtr, prio) - TkText *textPtr; /* Information about text widget. */ - TkTextTag *tagPtr; /* Tag whose priority is to be - * changed. */ - int prio; /* New priority for tag. */ -{ - int low, high, delta; - register TkTextTag *tagPtr2; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - - if (prio < 0) { - prio = 0; - } - if (prio >= textPtr->numTags) { - prio = textPtr->numTags-1; - } - if (prio == tagPtr->priority) { - return; - } else if (prio < tagPtr->priority) { - low = prio; - high = tagPtr->priority-1; - delta = 1; - } else { - low = tagPtr->priority+1; - high = prio; - delta = -1; - } - for (hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - tagPtr2 = (TkTextTag *) Tcl_GetHashValue(hPtr); - if ((tagPtr2->priority >= low) && (tagPtr2->priority <= high)) { - tagPtr2->priority += delta; - } - } - tagPtr->priority = prio; -} - -/* - *-------------------------------------------------------------- - * - * TkTextBindProc -- - * - * This procedure is invoked by the Tk dispatcher to handle - * events associated with bindings on items. - * - * Results: - * None. - * - * Side effects: - * Depends on the command invoked as part of the binding - * (if there was any). - * - *-------------------------------------------------------------- - */ - -void -TkTextBindProc(clientData, eventPtr) - ClientData clientData; /* Pointer to canvas structure. */ - XEvent *eventPtr; /* Pointer to X event that just - * happened. */ -{ - TkText *textPtr = (TkText *) clientData; - int repick = 0; - -# define AnyButtonMask (Button1Mask|Button2Mask|Button3Mask\ - |Button4Mask|Button5Mask) - - Tcl_Preserve((ClientData) textPtr); - - /* - * This code simulates grabs for mouse buttons by keeping track - * of whether a button is pressed and refusing to pick a new current - * character while a button is pressed. - */ - - if (eventPtr->type == ButtonPress) { - textPtr->flags |= BUTTON_DOWN; - } else if (eventPtr->type == ButtonRelease) { - int mask; - - switch (eventPtr->xbutton.button) { - case Button1: - mask = Button1Mask; - break; - case Button2: - mask = Button2Mask; - break; - case Button3: - mask = Button3Mask; - break; - case Button4: - mask = Button4Mask; - break; - case Button5: - mask = Button5Mask; - break; - default: - mask = 0; - break; - } - if ((eventPtr->xbutton.state & AnyButtonMask) == (unsigned) mask) { - textPtr->flags &= ~BUTTON_DOWN; - repick = 1; - } - } else if ((eventPtr->type == EnterNotify) - || (eventPtr->type == LeaveNotify)) { - if (eventPtr->xcrossing.state & AnyButtonMask) { - textPtr->flags |= BUTTON_DOWN; - } else { - textPtr->flags &= ~BUTTON_DOWN; - } - TkTextPickCurrent(textPtr, eventPtr); - goto done; - } else if (eventPtr->type == MotionNotify) { - if (eventPtr->xmotion.state & AnyButtonMask) { - textPtr->flags |= BUTTON_DOWN; - } else { - textPtr->flags &= ~BUTTON_DOWN; - } - TkTextPickCurrent(textPtr, eventPtr); - } - if ((textPtr->numCurTags > 0) && (textPtr->bindingTable != NULL) - && (textPtr->tkwin != NULL)) { - Tk_BindEvent(textPtr->bindingTable, eventPtr, textPtr->tkwin, - textPtr->numCurTags, (ClientData *) textPtr->curTagArrayPtr); - } - if (repick) { - unsigned int oldState; - - oldState = eventPtr->xbutton.state; - eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask - |Button3Mask|Button4Mask|Button5Mask); - TkTextPickCurrent(textPtr, eventPtr); - eventPtr->xbutton.state = oldState; - } - - done: - Tcl_Release((ClientData) textPtr); -} - -/* - *-------------------------------------------------------------- - * - * TkTextPickCurrent -- - * - * Find the character containing the coordinates in an event - * and place the "current" mark on that character. If the - * "current" mark has moved then generate a fake leave event - * on the old current character and a fake enter event on the new - * current character. - * - * Results: - * None. - * - * Side effects: - * The current mark for textPtr may change. If it does, - * then the commands associated with character entry and leave - * could do just about anything. For example, the text widget - * might be deleted. It is up to the caller to protect itself - * with calls to Tcl_Preserve and Tcl_Release. - * - *-------------------------------------------------------------- - */ - -void -TkTextPickCurrent(textPtr, eventPtr) - register TkText *textPtr; /* Text widget in which to select - * current character. */ - XEvent *eventPtr; /* Event describing location of - * mouse cursor. Must be EnterWindow, - * LeaveWindow, ButtonRelease, or - * MotionNotify. */ -{ - TkTextIndex index; - TkTextTag **oldArrayPtr, **newArrayPtr; - TkTextTag **copyArrayPtr = NULL; /* Initialization needed to prevent - * compiler warning. */ - - int numOldTags, numNewTags, i, j, size; - XEvent event; - - /* - * If a button is down, then don't do anything at all; we'll be - * called again when all buttons are up, and we can repick then. - * This implements a form of mouse grabbing. - */ - - if (textPtr->flags & BUTTON_DOWN) { - if (((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) - && ((eventPtr->xcrossing.mode == NotifyGrab) - || (eventPtr->xcrossing.mode == NotifyUngrab))) { - /* - * Special case: the window is being entered or left because - * of a grab or ungrab. In this case, repick after all. - * Furthermore, clear BUTTON_DOWN to release the simulated - * grab. - */ - - textPtr->flags &= ~BUTTON_DOWN; - } else { - return; - } - } - - /* - * Save information about this event in the widget in case we have - * to synthesize more enter and leave events later (e.g. because a - * character was deleted, causing a new character to be underneath - * the mouse cursor). Also translate MotionNotify events into - * EnterNotify events, since that's what gets reported to event - * handlers when the current character changes. - */ - - if (eventPtr != &textPtr->pickEvent) { - if ((eventPtr->type == MotionNotify) - || (eventPtr->type == ButtonRelease)) { - textPtr->pickEvent.xcrossing.type = EnterNotify; - textPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial; - textPtr->pickEvent.xcrossing.send_event - = eventPtr->xmotion.send_event; - textPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display; - textPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window; - textPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root; - textPtr->pickEvent.xcrossing.subwindow = None; - textPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time; - textPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x; - textPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y; - textPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root; - textPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root; - textPtr->pickEvent.xcrossing.mode = NotifyNormal; - textPtr->pickEvent.xcrossing.detail = NotifyNonlinear; - textPtr->pickEvent.xcrossing.same_screen - = eventPtr->xmotion.same_screen; - textPtr->pickEvent.xcrossing.focus = False; - textPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state; - } else { - textPtr->pickEvent = *eventPtr; - } - } - - /* - * Find the new current character, then find and sort all of the - * tags associated with it. - */ - - if (textPtr->pickEvent.type != LeaveNotify) { - TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x, - textPtr->pickEvent.xcrossing.y, &index); - newArrayPtr = TkBTreeGetTags(&index, &numNewTags); - SortTags(numNewTags, newArrayPtr); - } else { - newArrayPtr = NULL; - numNewTags = 0; - } - - /* - * Resort the tags associated with the previous marked character - * (the priorities might have changed), then make a copy of the - * new tags, and compare the old tags to the copy, nullifying - * any tags that are present in both groups (i.e. the tags that - * haven't changed). - */ - - SortTags(textPtr->numCurTags, textPtr->curTagArrayPtr); - if (numNewTags > 0) { - size = numNewTags * sizeof(TkTextTag *); - copyArrayPtr = (TkTextTag **) ckalloc((unsigned) size); - memcpy((VOID *) copyArrayPtr, (VOID *) newArrayPtr, (size_t) size); - for (i = 0; i < textPtr->numCurTags; i++) { - for (j = 0; j < numNewTags; j++) { - if (textPtr->curTagArrayPtr[i] == copyArrayPtr[j]) { - textPtr->curTagArrayPtr[i] = NULL; - copyArrayPtr[j] = NULL; - break; - } - } - } - } - - /* - * Invoke the binding system with a LeaveNotify event for all of - * the tags that have gone away. We have to be careful here, - * because it's possible that the binding could do something - * (like calling tkwait) that eventually modifies - * textPtr->curTagArrayPtr. To avoid problems in situations like - * this, update curTagArrayPtr to its new value before invoking - * any bindings, and don't use it any more here. - */ - - numOldTags = textPtr->numCurTags; - textPtr->numCurTags = numNewTags; - oldArrayPtr = textPtr->curTagArrayPtr; - textPtr->curTagArrayPtr = newArrayPtr; - if (numOldTags != 0) { - if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) { - event = textPtr->pickEvent; - event.type = LeaveNotify; - - /* - * Always use a detail of NotifyAncestor. Besides being - * consistent, this avoids problems where the binding code - * will discard NotifyInferior events. - */ - - event.xcrossing.detail = NotifyAncestor; - Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin, - numOldTags, (ClientData *) oldArrayPtr); - } - ckfree((char *) oldArrayPtr); - } - - /* - * Reset the "current" mark (be careful to recompute its location, - * since it might have changed during an event binding). Then - * invoke the binding system with an EnterNotify event for all of - * the tags that have just appeared. - */ - - TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x, - textPtr->pickEvent.xcrossing.y, &index); - TkTextSetMark(textPtr, "current", &index); - if (numNewTags != 0) { - if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) { - event = textPtr->pickEvent; - event.type = EnterNotify; - event.xcrossing.detail = NotifyAncestor; - Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin, - numNewTags, (ClientData *) copyArrayPtr); - } - ckfree((char *) copyArrayPtr); - } -} diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c deleted file mode 100644 index a799da4..0000000 --- a/generic/tkTextWind.c +++ /dev/null @@ -1,1176 +0,0 @@ -/* - * tkTextWind.c -- - * - * This file contains code that allows arbitrary windows to be - * nested inside text widgets. It also implements the "window" - * widget command for texts. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTextWind.c,v 1.2 1998/09/14 18:23:19 stanton Exp $ - */ - -#include "tk.h" -#include "tkText.h" -#include "tkPort.h" - -/* - * The following structure is the official type record for the - * embedded window geometry manager: - */ - -static void EmbWinRequestProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); -static void EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin)); - -static Tk_GeomMgr textGeomType = { - "text", /* name */ - EmbWinRequestProc, /* requestProc */ - EmbWinLostSlaveProc, /* lostSlaveProc */ -}; - -/* - * Definitions for alignment values: - */ - -#define ALIGN_BOTTOM 0 -#define ALIGN_CENTER 1 -#define ALIGN_TOP 2 -#define ALIGN_BASELINE 3 - -/* - * Macro that determines the size of an embedded window segment: - */ - -#define EW_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + sizeof(TkTextEmbWindow))) - -/* - * Prototypes for procedures defined in this file: - */ - -static int AlignParseProc _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, - char *widgRec, int offset)); -static char * AlignPrintProc _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin, char *widgRec, int offset, - Tcl_FreeProc **freeProcPtr)); -static TkTextSegment * EmbWinCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static void EmbWinCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -static void EmbWinBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, - int index, int y, int lineHeight, int baseline, - int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -static int EmbWinConfigure _ANSI_ARGS_((TkText *textPtr, - TkTextSegment *ewPtr, int argc, char **argv)); -static void EmbWinDelayedUnmap _ANSI_ARGS_(( - ClientData clientData)); -static int EmbWinDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone)); -static void EmbWinDisplayProc _ANSI_ARGS_(( - TkTextDispChunk *chunkPtr, int x, int y, - int lineHeight, int baseline, Display *display, - Drawable dst, int screenY)); -static int EmbWinLayoutProc _ANSI_ARGS_((TkText *textPtr, - TkTextIndex *indexPtr, TkTextSegment *segPtr, - int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, - TkTextDispChunk *chunkPtr)); -static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static void EmbWinUndisplayProc _ANSI_ARGS_((TkText *textPtr, - TkTextDispChunk *chunkPtr)); - -/* - * The following structure declares the "embedded window" segment type. - */ - -static Tk_SegType tkTextEmbWindowType = { - "window", /* name */ - 0, /* leftGravity */ - (Tk_SegSplitProc *) NULL, /* splitProc */ - EmbWinDeleteProc, /* deleteProc */ - EmbWinCleanupProc, /* cleanupProc */ - (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */ - EmbWinLayoutProc, /* layoutProc */ - EmbWinCheckProc /* checkProc */ -}; - -/* - * Information used for parsing window configuration options: - */ - -static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc, - (ClientData) NULL}; - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL, - "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption}, - {TK_CONFIG_STRING, "-create", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextEmbWindow, create), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-padx", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextEmbWindow, padX), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_INT, "-pady", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextEmbWindow, padY), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BOOLEAN, "-stretch", (char *) NULL, (char *) NULL, - "0", Tk_Offset(TkTextEmbWindow, stretch), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(TkTextEmbWindow, tkwin), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} -}; - -/* - *-------------------------------------------------------------- - * - * TkTextWindowCmd -- - * - * This procedure implements the "window" widget command - * for text widgets. See the user documentation for details - * on what it does. - * - * Results: - * A standard Tcl result or error. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextWindowCmd(textPtr, interp, argc, argv) - register TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. Someone else has already - * parsed this command enough to know that - * argv[1] is "window". */ -{ - size_t length; - register TkTextSegment *ewPtr; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window option ?arg arg ...?\"", (char *) NULL); - return TCL_ERROR; - } - length = strlen(argv[2]); - if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) { - TkTextIndex index; - TkTextSegment *ewPtr; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window cget index option\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - ewPtr = TkTextIndexToSeg(&index, (int *) NULL); - if (ewPtr->typePtr != &tkTextEmbWindowType) { - Tcl_AppendResult(interp, "no embedded window at index \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs, - (char *) &ewPtr->body.ew, argv[4], 0); - } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) { - TkTextIndex index; - TkTextSegment *ewPtr; - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window configure index ?option value ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - ewPtr = TkTextIndexToSeg(&index, (int *) NULL); - if (ewPtr->typePtr != &tkTextEmbWindowType) { - Tcl_AppendResult(interp, "no embedded window at index \"", - argv[3], "\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 4) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) &ewPtr->body.ew, (char *) NULL, 0); - } else if (argc == 5) { - return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs, - (char *) &ewPtr->body.ew, argv[4], 0); - } else { - TkTextChanged(textPtr, &index, &index); - return EmbWinConfigure(textPtr, ewPtr, argc-4, argv+4); - } - } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) { - TkTextIndex index; - int lineIndex; - - /* - * Add a new window. Find where to put the new window, and - * mark that position for redisplay. - */ - - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window create index ?option value ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Don't allow insertions on the last (dummy) line of the text. - */ - - lineIndex = TkBTreeLineIndex(index.linePtr); - if (lineIndex == TkBTreeNumLines(textPtr->tree)) { - lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index); - } - - /* - * Create the new window segment and initialize it. - */ - - ewPtr = (TkTextSegment *) ckalloc(EW_SEG_SIZE); - ewPtr->typePtr = &tkTextEmbWindowType; - ewPtr->size = 1; - ewPtr->body.ew.textPtr = textPtr; - ewPtr->body.ew.linePtr = NULL; - ewPtr->body.ew.tkwin = NULL; - ewPtr->body.ew.create = NULL; - ewPtr->body.ew.align = ALIGN_CENTER; - ewPtr->body.ew.padX = ewPtr->body.ew.padY = 0; - ewPtr->body.ew.stretch = 0; - ewPtr->body.ew.chunkCount = 0; - ewPtr->body.ew.displayed = 0; - - /* - * Link the segment into the text widget, then configure it (delete - * it again if the configuration fails). - */ - - TkTextChanged(textPtr, &index, &index); - TkBTreeLinkSegment(ewPtr, &index); - if (EmbWinConfigure(textPtr, ewPtr, argc-4, argv+4) != TCL_OK) { - TkTextIndex index2; - - TkTextIndexForwChars(&index, 1, &index2); - TkBTreeDeleteChars(&index, &index2); - return TCL_ERROR; - } - } else if (strncmp(argv[2], "names", length) == 0) { - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window names\"", (char *) NULL); - return TCL_ERROR; - } - for (hPtr = Tcl_FirstHashEntry(&textPtr->windowTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, - Tcl_GetHashKey(&textPtr->markTable, hPtr)); - } - } else { - Tcl_AppendResult(interp, "bad window option \"", argv[2], - "\": must be cget, configure, create, or names", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * EmbWinConfigure -- - * - * This procedure is called to handle configuration options - * for an embedded window, using an argc/argv list. - * - * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message.. - * - * Side effects: - * Configuration information for the embedded window changes, - * such as alignment, stretching, or name of the embedded - * window. - * - *-------------------------------------------------------------- - */ - -static int -EmbWinConfigure(textPtr, ewPtr, argc, argv) - TkText *textPtr; /* Information about text widget that - * contains embedded window. */ - TkTextSegment *ewPtr; /* Embedded window to be configured. */ - int argc; /* Number of strings in argv. */ - char **argv; /* Array of strings describing configuration - * options. */ -{ - Tk_Window oldWindow; - Tcl_HashEntry *hPtr; - int new; - - oldWindow = ewPtr->body.ew.tkwin; - if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs, - argc, argv, (char *) &ewPtr->body.ew, TK_CONFIG_ARGV_ONLY) - != TCL_OK) { - return TCL_ERROR; - } - if (oldWindow != ewPtr->body.ew.tkwin) { - if (oldWindow != NULL) { - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&textPtr->windowTable, - Tk_PathName(oldWindow))); - Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, - EmbWinStructureProc, (ClientData) ewPtr); - Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL, - (ClientData) NULL); - if (textPtr->tkwin != Tk_Parent(oldWindow)) { - Tk_UnmaintainGeometry(oldWindow, textPtr->tkwin); - } else { - Tk_UnmapWindow(oldWindow); - } - } - if (ewPtr->body.ew.tkwin != NULL) { - Tk_Window ancestor, parent; - - /* - * Make sure that the text is either the parent of the - * embedded window or a descendant of that parent. Also, - * don't allow a top-level window to be managed inside - * a text. - */ - - parent = Tk_Parent(ewPtr->body.ew.tkwin); - for (ancestor = textPtr->tkwin; ; - ancestor = Tk_Parent(ancestor)) { - if (ancestor == parent) { - break; - } - if (Tk_IsTopLevel(ancestor)) { - badMaster: - Tcl_AppendResult(textPtr->interp, "can't embed ", - Tk_PathName(ewPtr->body.ew.tkwin), " in ", - Tk_PathName(textPtr->tkwin), (char *) NULL); - ewPtr->body.ew.tkwin = NULL; - return TCL_ERROR; - } - } - if (Tk_IsTopLevel(ewPtr->body.ew.tkwin) - || (ewPtr->body.ew.tkwin == textPtr->tkwin)) { - goto badMaster; - } - - /* - * Take over geometry management for the window, plus create - * an event handler to find out when it is deleted. - */ - - Tk_ManageGeometry(ewPtr->body.ew.tkwin, &textGeomType, - (ClientData) ewPtr); - Tk_CreateEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask, - EmbWinStructureProc, (ClientData) ewPtr); - - /* - * Special trick! Must enter into the hash table *after* - * calling Tk_ManageGeometry: if the window was already managed - * elsewhere in this text, the Tk_ManageGeometry call will cause - * the entry to be removed, which could potentially lose the new - * entry. - */ - - hPtr = Tcl_CreateHashEntry(&textPtr->windowTable, - Tk_PathName(ewPtr->body.ew.tkwin), &new); - Tcl_SetHashValue(hPtr, ewPtr); - - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * AlignParseProc -- - * - * This procedure is invoked by Tk_ConfigureWidget during - * option processing to handle "-align" options for embedded - * windows. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * The alignment for the embedded window may change. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -AlignParseProc(clientData, interp, tkwin, value, widgRec, offset) - ClientData clientData; /* Not used.*/ - Tcl_Interp *interp; /* Used for reporting errors. */ - Tk_Window tkwin; /* Window for text widget. */ - char *value; /* Value of option. */ - char *widgRec; /* Pointer to TkTextEmbWindow - * structure. */ - int offset; /* Offset into item (ignored). */ -{ - register TkTextEmbWindow *embPtr = (TkTextEmbWindow *) widgRec; - - if (strcmp(value, "baseline") == 0) { - embPtr->align = ALIGN_BASELINE; - } else if (strcmp(value, "bottom") == 0) { - embPtr->align = ALIGN_BOTTOM; - } else if (strcmp(value, "center") == 0) { - embPtr->align = ALIGN_CENTER; - } else if (strcmp(value, "top") == 0) { - embPtr->align = ALIGN_TOP; - } else { - Tcl_AppendResult(interp, "bad alignment \"", value, - "\": must be baseline, bottom, center, or top", - (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * AlignPrintProc -- - * - * This procedure is invoked by the Tk configuration code - * to produce a printable string for the "-align" configuration - * option for embedded windows. - * - * Results: - * The return value is a string describing the embedded - * window's current alignment. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static char * -AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) - ClientData clientData; /* Ignored. */ - Tk_Window tkwin; /* Window for text widget. */ - char *widgRec; /* Pointer to TkTextEmbWindow - * structure. */ - int offset; /* Ignored. */ - Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with - * information about how to reclaim - * storage for return string. */ -{ - switch (((TkTextEmbWindow *) widgRec)->align) { - case ALIGN_BASELINE: - return "baseline"; - case ALIGN_BOTTOM: - return "bottom"; - case ALIGN_CENTER: - return "center"; - case ALIGN_TOP: - return "top"; - default: - return "??"; - } -} - -/* - *-------------------------------------------------------------- - * - * EmbWinStructureProc -- - * - * This procedure is invoked by the Tk event loop whenever - * StructureNotify events occur for a window that's embedded - * in a text widget. This procedure's only purpose is to - * clean up when windows are deleted. - * - * Results: - * None. - * - * Side effects: - * The window is disassociated from the window segment, and - * the portion of the text is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinStructureProc(clientData, eventPtr) - ClientData clientData; /* Pointer to record describing window item. */ - XEvent *eventPtr; /* Describes what just happened. */ -{ - register TkTextSegment *ewPtr = (TkTextSegment *) clientData; - TkTextIndex index; - - if (eventPtr->type != DestroyNotify) { - return; - } - - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable, - Tk_PathName(ewPtr->body.ew.tkwin))); - ewPtr->body.ew.tkwin = NULL; - index.tree = ewPtr->body.ew.textPtr->tree; - index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); - TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); -} - -/* - *-------------------------------------------------------------- - * - * EmbWinRequestProc -- - * - * This procedure is invoked whenever a window that's associated - * with a window canvas item changes its requested dimensions. - * - * Results: - * None. - * - * Side effects: - * The size and location on the screen of the window may change, - * depending on the options specified for the window item. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -EmbWinRequestProc(clientData, tkwin) - ClientData clientData; /* Pointer to record for window item. */ - Tk_Window tkwin; /* Window that changed its desired - * size. */ -{ - TkTextSegment *ewPtr = (TkTextSegment *) clientData; - TkTextIndex index; - - index.tree = ewPtr->body.ew.textPtr->tree; - index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); - TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); -} - -/* - *-------------------------------------------------------------- - * - * EmbWinLostSlaveProc -- - * - * This procedure is invoked by the Tk geometry manager when - * a slave window managed by a text widget is claimed away - * by another geometry manager. - * - * Results: - * None. - * - * Side effects: - * The window is disassociated from the window segment, and - * the portion of the text is redisplayed. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinLostSlaveProc(clientData, tkwin) - ClientData clientData; /* Pointer to record describing window item. */ - Tk_Window tkwin; /* Window that was claimed away by another - * geometry manager. */ -{ - register TkTextSegment *ewPtr = (TkTextSegment *) clientData; - TkTextIndex index; - - Tk_DeleteEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask, - EmbWinStructureProc, (ClientData) ewPtr); - Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); - if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(tkwin)) { - Tk_UnmaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin); - } else { - Tk_UnmapWindow(tkwin); - } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable, - Tk_PathName(ewPtr->body.ew.tkwin))); - ewPtr->body.ew.tkwin = NULL; - index.tree = ewPtr->body.ew.textPtr->tree; - index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); - TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); -} - -/* - *-------------------------------------------------------------- - * - * EmbWinDeleteProc -- - * - * This procedure is invoked by the text B-tree code whenever - * an embedded window lies in a range of characters being deleted. - * - * Results: - * Returns 0 to indicate that the deletion has been accepted. - * - * Side effects: - * The embedded window is deleted, if it exists, and any resources - * associated with it are released. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -EmbWinDeleteProc(ewPtr, linePtr, treeGone) - TkTextSegment *ewPtr; /* Segment being deleted. */ - TkTextLine *linePtr; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ -{ - Tcl_HashEntry *hPtr; - - if (ewPtr->body.ew.tkwin != NULL) { - hPtr = Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable, - Tk_PathName(ewPtr->body.ew.tkwin)); - if (hPtr != NULL) { - /* - * (It's possible for there to be no hash table entry for this - * window, if an error occurred while creating the window segment - * but before the window got added to the table) - */ - - Tcl_DeleteHashEntry(hPtr); - } - - /* - * Delete the event handler for the window before destroying - * the window, so that EmbWinStructureProc doesn't get called - * (we'll already do everything that it would have done, and - * it will just get confused). - */ - - Tk_DeleteEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask, - EmbWinStructureProc, (ClientData) ewPtr); - Tk_DestroyWindow(ewPtr->body.ew.tkwin); - } - Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); - Tk_FreeOptions(configSpecs, (char *) &ewPtr->body.ew, - ewPtr->body.ew.textPtr->display, 0); - ckfree((char *) ewPtr); - return 0; -} - -/* - *-------------------------------------------------------------- - * - * EmbWinCleanupProc -- - * - * This procedure is invoked by the B-tree code whenever a - * segment containing an embedded window is moved from one - * line to another. - * - * Results: - * None. - * - * Side effects: - * The linePtr field of the segment gets updated. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -EmbWinCleanupProc(ewPtr, linePtr) - TkTextSegment *ewPtr; /* Mark segment that's being moved. */ - TkTextLine *linePtr; /* Line that now contains segment. */ -{ - ewPtr->body.ew.linePtr = linePtr; - return ewPtr; -} - -/* - *-------------------------------------------------------------- - * - * EmbWinLayoutProc -- - * - * This procedure is the "layoutProc" for embedded window - * segments. - * - * Results: - * 1 is returned to indicate that the segment should be - * displayed. The chunkPtr structure is filled in. - * - * Side effects: - * None, except for filling in chunkPtr. - * - *-------------------------------------------------------------- - */ - - /*ARGSUSED*/ -static int -EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, - noCharsYet, wrapMode, chunkPtr) - TkText *textPtr; /* Text widget being layed out. */ - TkTextIndex *indexPtr; /* Identifies first character in chunk. */ - TkTextSegment *ewPtr; /* Segment corresponding to indexPtr. */ - int offset; /* Offset within segPtr corresponding to - * indexPtr (always 0). */ - int maxX; /* Chunk must not occupy pixels at this - * position or higher. */ - int maxChars; /* Chunk must not include more than this - * many characters. */ - int noCharsYet; /* Non-zero means no characters have been - * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ - register TkTextDispChunk *chunkPtr; - /* Structure to fill in with information - * about this chunk. The x field has already - * been set by the caller. */ -{ - int width, height; - - if (offset != 0) { - panic("Non-zero offset in EmbWinLayoutProc"); - } - - if ((ewPtr->body.ew.tkwin == NULL) && (ewPtr->body.ew.create != NULL)) { - int code, new; - Tcl_DString name; - Tk_Window ancestor; - Tcl_HashEntry *hPtr; - - /* - * The window doesn't currently exist. Create it by evaluating - * the creation script. The script must return the window's - * path name: look up that name to get back to the window - * token. Then register ourselves as the geometry manager for - * the window. - */ - - code = Tcl_GlobalEval(textPtr->interp, ewPtr->body.ew.create); - if (code != TCL_OK) { - createError: - Tcl_BackgroundError(textPtr->interp); - goto gotWindow; - } - Tcl_DStringInit(&name); - Tcl_DStringAppend(&name, textPtr->interp->result, -1); - Tcl_ResetResult(textPtr->interp); - ewPtr->body.ew.tkwin = Tk_NameToWindow(textPtr->interp, - Tcl_DStringValue(&name), textPtr->tkwin); - if (ewPtr->body.ew.tkwin == NULL) { - goto createError; - } - for (ancestor = textPtr->tkwin; ; - ancestor = Tk_Parent(ancestor)) { - if (ancestor == Tk_Parent(ewPtr->body.ew.tkwin)) { - break; - } - if (Tk_IsTopLevel(ancestor)) { - badMaster: - Tcl_AppendResult(textPtr->interp, "can't embed ", - Tk_PathName(ewPtr->body.ew.tkwin), " relative to ", - Tk_PathName(textPtr->tkwin), (char *) NULL); - Tcl_BackgroundError(textPtr->interp); - ewPtr->body.ew.tkwin = NULL; - goto gotWindow; - } - } - if (Tk_IsTopLevel(ewPtr->body.ew.tkwin) - || (textPtr->tkwin == ewPtr->body.ew.tkwin)) { - goto badMaster; - } - Tk_ManageGeometry(ewPtr->body.ew.tkwin, &textGeomType, - (ClientData) ewPtr); - Tk_CreateEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask, - EmbWinStructureProc, (ClientData) ewPtr); - - /* - * Special trick! Must enter into the hash table *after* - * calling Tk_ManageGeometry: if the window was already managed - * elsewhere in this text, the Tk_ManageGeometry call will cause - * the entry to be removed, which could potentially lose the new - * entry. - */ - - hPtr = Tcl_CreateHashEntry(&textPtr->windowTable, - Tk_PathName(ewPtr->body.ew.tkwin), &new); - Tcl_SetHashValue(hPtr, ewPtr); - } - - /* - * See if there's room for this window on this line. - */ - - gotWindow: - if (ewPtr->body.ew.tkwin == NULL) { - width = 0; - height = 0; - } else { - width = Tk_ReqWidth(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padX; - height = Tk_ReqHeight(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padY; - } - if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) { - return 0; - } - - /* - * Fill in the chunk structure. - */ - - chunkPtr->displayProc = EmbWinDisplayProc; - chunkPtr->undisplayProc = EmbWinUndisplayProc; - chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; - chunkPtr->bboxProc = EmbWinBboxProc; - chunkPtr->numChars = 1; - if (ewPtr->body.ew.align == ALIGN_BASELINE) { - chunkPtr->minAscent = height - ewPtr->body.ew.padY; - chunkPtr->minDescent = ewPtr->body.ew.padY; - chunkPtr->minHeight = 0; - } else { - chunkPtr->minAscent = 0; - chunkPtr->minDescent = 0; - chunkPtr->minHeight = height; - } - chunkPtr->width = width; - chunkPtr->breakIndex = -1; - chunkPtr->breakIndex = 1; - chunkPtr->clientData = (ClientData) ewPtr; - ewPtr->body.ew.chunkCount += 1; - return 1; -} - -/* - *-------------------------------------------------------------- - * - * EmbWinCheckProc -- - * - * This procedure is invoked by the B-tree code to perform - * consistency checks on embedded windows. - * - * Results: - * None. - * - * Side effects: - * The procedure panics if it detects anything wrong with - * the embedded window. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinCheckProc(ewPtr, linePtr) - TkTextSegment *ewPtr; /* Segment to check. */ - TkTextLine *linePtr; /* Line containing segment. */ -{ - if (ewPtr->nextPtr == NULL) { - panic("EmbWinCheckProc: embedded window is last segment in line"); - } - if (ewPtr->size != 1) { - panic("EmbWinCheckProc: embedded window has size %d", ewPtr->size); - } -} - -/* - *-------------------------------------------------------------- - * - * EmbWinDisplayProc -- - * - * This procedure is invoked by the text displaying code - * when it is time to actually draw an embedded window - * chunk on the screen. - * - * Results: - * None. - * - * Side effects: - * The embedded window gets moved to the correct location - * and mapped onto the screen. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY) - TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */ - int x; /* X-position in dst at which to - * draw this chunk (differs from - * the x-position in the chunk because - * of scrolling). */ - int y; /* Top of rectangular bounding box - * for line: tells where to draw this - * chunk in dst (x-position is in - * the chunk itself). */ - int lineHeight; /* Total height of line. */ - int baseline; /* Offset of baseline from y. */ - Display *display; /* Display to use for drawing. */ - Drawable dst; /* Pixmap or window in which to draw */ - int screenY; /* Y-coordinate in text window that - * corresponds to y. */ -{ - TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData; - int lineX, windowX, windowY, width, height; - Tk_Window tkwin; - - tkwin = ewPtr->body.ew.tkwin; - if (tkwin == NULL) { - return; - } - if ((x + chunkPtr->width) <= 0) { - /* - * The window is off-screen; just unmap it. - */ - - if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(tkwin)) { - Tk_UnmaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin); - } else { - Tk_UnmapWindow(tkwin); - } - return; - } - - /* - * Compute the window's location and size in the text widget, taking - * into account the align and stretch values for the window. - */ - - EmbWinBboxProc(chunkPtr, 0, screenY, lineHeight, baseline, &lineX, - &windowY, &width, &height); - windowX = lineX - chunkPtr->x + x; - - if (ewPtr->body.ew.textPtr->tkwin == Tk_Parent(tkwin)) { - if ((windowX != Tk_X(tkwin)) || (windowY != Tk_Y(tkwin)) - || (Tk_ReqWidth(tkwin) != Tk_Width(tkwin)) - || (height != Tk_Height(tkwin))) { - Tk_MoveResizeWindow(tkwin, windowX, windowY, width, height); - } - Tk_MapWindow(tkwin); - } else { - Tk_MaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin, - windowX, windowY, width, height); - } - - /* - * Mark the window as displayed so that it won't get unmapped. - */ - - ewPtr->body.ew.displayed = 1; -} - -/* - *-------------------------------------------------------------- - * - * EmbWinUndisplayProc -- - * - * This procedure is called when the chunk for an embedded - * window is no longer going to be displayed. It arranges - * for the window associated with the chunk to be unmapped. - * - * Results: - * None. - * - * Side effects: - * The window is scheduled for unmapping. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinUndisplayProc(textPtr, chunkPtr) - TkText *textPtr; /* Overall information about text - * widget. */ - TkTextDispChunk *chunkPtr; /* Chunk that is about to be freed. */ -{ - TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData; - - ewPtr->body.ew.chunkCount--; - if (ewPtr->body.ew.chunkCount == 0) { - /* - * Don't unmap the window immediately, since there's a good chance - * that it will immediately be redisplayed, perhaps even in the - * same place. Instead, schedule the window to be unmapped later; - * the call to EmbWinDelayedUnmap will be cancelled in the likely - * event that the unmap becomes unnecessary. - */ - - ewPtr->body.ew.displayed = 0; - Tcl_DoWhenIdle(EmbWinDelayedUnmap, (ClientData) ewPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * EmbWinBboxProc -- - * - * This procedure is called to compute the bounding box of - * the area occupied by an embedded window. - * - * Results: - * There is no return value. *xPtr and *yPtr are filled in - * with the coordinates of the upper left corner of the - * window, and *widthPtr and *heightPtr are filled in with - * the dimensions of the window in pixels. Note: not all - * of the returned bbox is necessarily visible on the screen - * (the rightmost part might be off-screen to the right, - * and the bottommost part might be off-screen to the bottom). - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, - widthPtr, heightPtr) - TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ - int index; /* Index of desired character within - * the chunk. */ - int y; /* Topmost pixel in area allocated - * for this line. */ - int lineHeight; /* Total height of line. */ - int baseline; /* Location of line's baseline, in - * pixels measured down from y. */ - int *xPtr, *yPtr; /* Gets filled in with coords of - * character's upper-left pixel. */ - int *widthPtr; /* Gets filled in with width of - * character, in pixels. */ - int *heightPtr; /* Gets filled in with height of - * character, in pixels. */ -{ - TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData; - Tk_Window tkwin; - - tkwin = ewPtr->body.ew.tkwin; - if (tkwin != NULL) { - *widthPtr = Tk_ReqWidth(tkwin); - *heightPtr = Tk_ReqHeight(tkwin); - } else { - *widthPtr = 0; - *heightPtr = 0; - } - *xPtr = chunkPtr->x + ewPtr->body.ew.padX; - if (ewPtr->body.ew.stretch) { - if (ewPtr->body.ew.align == ALIGN_BASELINE) { - *heightPtr = baseline - ewPtr->body.ew.padY; - } else { - *heightPtr = lineHeight - 2*ewPtr->body.ew.padY; - } - } - switch (ewPtr->body.ew.align) { - case ALIGN_BOTTOM: - *yPtr = y + (lineHeight - *heightPtr - ewPtr->body.ew.padY); - break; - case ALIGN_CENTER: - *yPtr = y + (lineHeight - *heightPtr)/2; - break; - case ALIGN_TOP: - *yPtr = y + ewPtr->body.ew.padY; - break; - case ALIGN_BASELINE: - *yPtr = y + (baseline - *heightPtr); - break; - } -} - -/* - *-------------------------------------------------------------- - * - * EmbWinDelayedUnmap -- - * - * This procedure is an idle handler that does the actual - * work of unmapping an embedded window. See the comment - * in EmbWinUndisplayProc for details. - * - * Results: - * None. - * - * Side effects: - * The window gets unmapped, unless its chunk reference count - * has become non-zero again. - * - *-------------------------------------------------------------- - */ - -static void -EmbWinDelayedUnmap(clientData) - ClientData clientData; /* Token for the window to - * be unmapped. */ -{ - TkTextSegment *ewPtr = (TkTextSegment *) clientData; - - if (!ewPtr->body.ew.displayed && (ewPtr->body.ew.tkwin != NULL)) { - if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(ewPtr->body.ew.tkwin)) { - Tk_UnmaintainGeometry(ewPtr->body.ew.tkwin, - ewPtr->body.ew.textPtr->tkwin); - } else { - Tk_UnmapWindow(ewPtr->body.ew.tkwin); - } - } -} - -/* - *-------------------------------------------------------------- - * - * TkTextWindowIndex -- - * - * Given the name of an embedded window within a text widget, - * returns an index corresponding to the window's position - * in the text. - * - * Results: - * The return value is 1 if there is an embedded window by - * the given name in the text widget, 0 otherwise. If the - * window exists, *indexPtr is filled in with its index. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextWindowIndex(textPtr, name, indexPtr) - TkText *textPtr; /* Text widget containing window. */ - char *name; /* Name of window. */ - TkTextIndex *indexPtr; /* Index information gets stored here. */ -{ - Tcl_HashEntry *hPtr; - TkTextSegment *ewPtr; - - hPtr = Tcl_FindHashEntry(&textPtr->windowTable, name); - if (hPtr == NULL) { - return 0; - } - ewPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - indexPtr->tree = textPtr->tree; - indexPtr->linePtr = ewPtr->body.ew.linePtr; - indexPtr->charIndex = TkTextSegToOffset(ewPtr, indexPtr->linePtr); - return 1; -} diff --git a/generic/tkTrig.c b/generic/tkTrig.c deleted file mode 100644 index 920bcc0..0000000 --- a/generic/tkTrig.c +++ /dev/null @@ -1,1467 +0,0 @@ -/* - * tkTrig.c -- - * - * This file contains a collection of trigonometry utility - * routines that are used by Tk and in particular by the - * canvas code. It also has miscellaneous geometry functions - * used by canvases. - * - * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkTrig.c,v 1.2 1998/09/14 18:23:20 stanton Exp $ - */ - -#include <stdio.h> -#include "tkInt.h" -#include "tkPort.h" -#include "tkCanvas.h" - -#undef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#undef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#ifndef PI -# define PI 3.14159265358979323846 -#endif /* PI */ - -/* - *-------------------------------------------------------------- - * - * TkLineToPoint -- - * - * Compute the distance from a point to a finite line segment. - * - * Results: - * The return value is the distance from the line segment - * whose end-points are *end1Ptr and *end2Ptr to the point - * given by *pointPtr. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -double -TkLineToPoint(end1Ptr, end2Ptr, pointPtr) - double end1Ptr[2]; /* Coordinates of first end-point of line. */ - double end2Ptr[2]; /* Coordinates of second end-point of line. */ - double pointPtr[2]; /* Points to coords for point. */ -{ - double x, y; - - /* - * Compute the point on the line that is closest to the - * point. This must be done separately for vertical edges, - * horizontal edges, and other edges. - */ - - if (end1Ptr[0] == end2Ptr[0]) { - - /* - * Vertical edge. - */ - - x = end1Ptr[0]; - if (end1Ptr[1] >= end2Ptr[1]) { - y = MIN(end1Ptr[1], pointPtr[1]); - y = MAX(y, end2Ptr[1]); - } else { - y = MIN(end2Ptr[1], pointPtr[1]); - y = MAX(y, end1Ptr[1]); - } - } else if (end1Ptr[1] == end2Ptr[1]) { - - /* - * Horizontal edge. - */ - - y = end1Ptr[1]; - if (end1Ptr[0] >= end2Ptr[0]) { - x = MIN(end1Ptr[0], pointPtr[0]); - x = MAX(x, end2Ptr[0]); - } else { - x = MIN(end2Ptr[0], pointPtr[0]); - x = MAX(x, end1Ptr[0]); - } - } else { - double m1, b1, m2, b2; - - /* - * The edge is neither horizontal nor vertical. Convert the - * edge to a line equation of the form y = m1*x + b1. Then - * compute a line perpendicular to this edge but passing - * through the point, also in the form y = m2*x + b2. - */ - - m1 = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]); - b1 = end1Ptr[1] - m1*end1Ptr[0]; - m2 = -1.0/m1; - b2 = pointPtr[1] - m2*pointPtr[0]; - x = (b2 - b1)/(m1 - m2); - y = m1*x + b1; - if (end1Ptr[0] > end2Ptr[0]) { - if (x > end1Ptr[0]) { - x = end1Ptr[0]; - y = end1Ptr[1]; - } else if (x < end2Ptr[0]) { - x = end2Ptr[0]; - y = end2Ptr[1]; - } - } else { - if (x > end2Ptr[0]) { - x = end2Ptr[0]; - y = end2Ptr[1]; - } else if (x < end1Ptr[0]) { - x = end1Ptr[0]; - y = end1Ptr[1]; - } - } - } - - /* - * Compute the distance to the closest point. - */ - - return hypot(pointPtr[0] - x, pointPtr[1] - y); -} - -/* - *-------------------------------------------------------------- - * - * TkLineToArea -- - * - * Determine whether a line lies entirely inside, entirely - * outside, or overlapping a given rectangular area. - * - * Results: - * -1 is returned if the line given by end1Ptr and end2Ptr - * is entirely outside the rectangle given by rectPtr. 0 is - * returned if the polygon overlaps the rectangle, and 1 is - * returned if the polygon is entirely inside the rectangle. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkLineToArea(end1Ptr, end2Ptr, rectPtr) - double end1Ptr[2]; /* X and y coordinates for one endpoint - * of line. */ - double end2Ptr[2]; /* X and y coordinates for other endpoint - * of line. */ - double rectPtr[4]; /* Points to coords for rectangle, in the - * order x1, y1, x2, y2. X1 must be no - * larger than x2, and y1 no larger than y2. */ -{ - int inside1, inside2; - - /* - * First check the two points individually to see whether they - * are inside the rectangle or not. - */ - - inside1 = (end1Ptr[0] >= rectPtr[0]) && (end1Ptr[0] <= rectPtr[2]) - && (end1Ptr[1] >= rectPtr[1]) && (end1Ptr[1] <= rectPtr[3]); - inside2 = (end2Ptr[0] >= rectPtr[0]) && (end2Ptr[0] <= rectPtr[2]) - && (end2Ptr[1] >= rectPtr[1]) && (end2Ptr[1] <= rectPtr[3]); - if (inside1 != inside2) { - return 0; - } - if (inside1 & inside2) { - return 1; - } - - /* - * Both points are outside the rectangle, but still need to check - * for intersections between the line and the rectangle. Horizontal - * and vertical lines are particularly easy, so handle them - * separately. - */ - - if (end1Ptr[0] == end2Ptr[0]) { - /* - * Vertical line. - */ - - if (((end1Ptr[1] >= rectPtr[1]) ^ (end2Ptr[1] >= rectPtr[1])) - && (end1Ptr[0] >= rectPtr[0]) - && (end1Ptr[0] <= rectPtr[2])) { - return 0; - } - } else if (end1Ptr[1] == end2Ptr[1]) { - /* - * Horizontal line. - */ - - if (((end1Ptr[0] >= rectPtr[0]) ^ (end2Ptr[0] >= rectPtr[0])) - && (end1Ptr[1] >= rectPtr[1]) - && (end1Ptr[1] <= rectPtr[3])) { - return 0; - } - } else { - double m, x, y, low, high; - - /* - * Diagonal line. Compute slope of line and use - * for intersection checks against each of the - * sides of the rectangle: left, right, bottom, top. - */ - - m = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]); - if (end1Ptr[0] < end2Ptr[0]) { - low = end1Ptr[0]; high = end2Ptr[0]; - } else { - low = end2Ptr[0]; high = end1Ptr[0]; - } - - /* - * Left edge. - */ - - y = end1Ptr[1] + (rectPtr[0] - end1Ptr[0])*m; - if ((rectPtr[0] >= low) && (rectPtr[0] <= high) - && (y >= rectPtr[1]) && (y <= rectPtr[3])) { - return 0; - } - - /* - * Right edge. - */ - - y += (rectPtr[2] - rectPtr[0])*m; - if ((y >= rectPtr[1]) && (y <= rectPtr[3]) - && (rectPtr[2] >= low) && (rectPtr[2] <= high)) { - return 0; - } - - /* - * Bottom edge. - */ - - if (end1Ptr[1] < end2Ptr[1]) { - low = end1Ptr[1]; high = end2Ptr[1]; - } else { - low = end2Ptr[1]; high = end1Ptr[1]; - } - x = end1Ptr[0] + (rectPtr[1] - end1Ptr[1])/m; - if ((x >= rectPtr[0]) && (x <= rectPtr[2]) - && (rectPtr[1] >= low) && (rectPtr[1] <= high)) { - return 0; - } - - /* - * Top edge. - */ - - x += (rectPtr[3] - rectPtr[1])/m; - if ((x >= rectPtr[0]) && (x <= rectPtr[2]) - && (rectPtr[3] >= low) && (rectPtr[3] <= high)) { - return 0; - } - } - return -1; -} - -/* - *-------------------------------------------------------------- - * - * TkThickPolyLineToArea -- - * - * This procedure is called to determine whether a connected - * series of line segments lies entirely inside, entirely - * outside, or overlapping a given rectangular area. - * - * Results: - * -1 is returned if the lines are entirely outside the area, - * 0 if they overlap, and 1 if they are entirely inside the - * given area. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -TkThickPolyLineToArea(coordPtr, numPoints, width, capStyle, joinStyle, rectPtr) - double *coordPtr; /* Points to an array of coordinates for - * the polyline: x0, y0, x1, y1, ... */ - int numPoints; /* Total number of points at *coordPtr. */ - double width; /* Width of each line segment. */ - int capStyle; /* How are end-points of polyline drawn? - * CapRound, CapButt, or CapProjecting. */ - int joinStyle; /* How are joints in polyline drawn? - * JoinMiter, JoinRound, or JoinBevel. */ - double *rectPtr; /* Rectangular area to check against. */ -{ - double radius, poly[10]; - int count; - int changedMiterToBevel; /* Non-zero means that a mitered corner - * had to be treated as beveled after all - * because the angle was < 11 degrees. */ - int inside; /* Tentative guess about what to return, - * based on all points seen so far: one - * means everything seen so far was - * inside the area; -1 means everything - * was outside the area. 0 means overlap - * has been found. */ - - radius = width/2.0; - inside = -1; - - if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2]) - && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) { - inside = 1; - } - - /* - * Iterate through all of the edges of the line, computing a polygon - * for each edge and testing the area against that polygon. In - * addition, there are additional tests to deal with rounded joints - * and caps. - */ - - changedMiterToBevel = 0; - for (count = numPoints; count >= 2; count--, coordPtr += 2) { - - /* - * If rounding is done around the first point of the edge - * then test a circular region around the point with the - * area. - */ - - if (((capStyle == CapRound) && (count == numPoints)) - || ((joinStyle == JoinRound) && (count != numPoints))) { - poly[0] = coordPtr[0] - radius; - poly[1] = coordPtr[1] - radius; - poly[2] = coordPtr[0] + radius; - poly[3] = coordPtr[1] + radius; - if (TkOvalToArea(poly, rectPtr) != inside) { - return 0; - } - } - - /* - * Compute the polygonal shape corresponding to this edge, - * consisting of two points for the first point of the edge - * and two points for the last point of the edge. - */ - - if (count == numPoints) { - TkGetButtPoints(coordPtr+2, coordPtr, width, - capStyle == CapProjecting, poly, poly+2); - } else if ((joinStyle == JoinMiter) && !changedMiterToBevel) { - poly[0] = poly[6]; - poly[1] = poly[7]; - poly[2] = poly[4]; - poly[3] = poly[5]; - } else { - TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2); - - /* - * If the last joint was beveled, then also check a - * polygon comprising the last two points of the previous - * polygon and the first two from this polygon; this checks - * the wedges that fill the beveled joint. - */ - - if ((joinStyle == JoinBevel) || changedMiterToBevel) { - poly[8] = poly[0]; - poly[9] = poly[1]; - if (TkPolygonToArea(poly, 5, rectPtr) != inside) { - return 0; - } - changedMiterToBevel = 0; - } - } - if (count == 2) { - TkGetButtPoints(coordPtr, coordPtr+2, width, - capStyle == CapProjecting, poly+4, poly+6); - } else if (joinStyle == JoinMiter) { - if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) width, poly+4, poly+6) == 0) { - changedMiterToBevel = 1; - TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, - poly+6); - } - } else { - TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); - } - poly[8] = poly[0]; - poly[9] = poly[1]; - if (TkPolygonToArea(poly, 5, rectPtr) != inside) { - return 0; - } - } - - /* - * If caps are rounded, check the cap around the final point - * of the line. - */ - - if (capStyle == CapRound) { - poly[0] = coordPtr[0] - radius; - poly[1] = coordPtr[1] - radius; - poly[2] = coordPtr[0] + radius; - poly[3] = coordPtr[1] + radius; - if (TkOvalToArea(poly, rectPtr) != inside) { - return 0; - } - } - - return inside; -} - -/* - *-------------------------------------------------------------- - * - * TkPolygonToPoint -- - * - * Compute the distance from a point to a polygon. - * - * Results: - * The return value is 0.0 if the point referred to by - * pointPtr is within the polygon referred to by polyPtr - * and numPoints. Otherwise the return value is the - * distance of the point from the polygon. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -double -TkPolygonToPoint(polyPtr, numPoints, pointPtr) - double *polyPtr; /* Points to an array coordinates for - * closed polygon: x0, y0, x1, y1, ... - * The polygon may be self-intersecting. */ - int numPoints; /* Total number of points at *polyPtr. */ - double *pointPtr; /* Points to coords for point. */ -{ - double bestDist; /* Closest distance between point and - * any edge in polygon. */ - int intersections; /* Number of edges in the polygon that - * intersect a ray extending vertically - * upwards from the point to infinity. */ - int count; - register double *pPtr; - - /* - * Iterate through all of the edges in the polygon, updating - * bestDist and intersections. - * - * TRICKY POINT: when computing intersections, include left - * x-coordinate of line within its range, but not y-coordinate. - * Otherwise if the point lies exactly below a vertex we'll - * count it as two intersections. - */ - - bestDist = 1.0e36; - intersections = 0; - - for (count = numPoints, pPtr = polyPtr; count > 1; count--, pPtr += 2) { - double x, y, dist; - - /* - * Compute the point on the current edge closest to the point - * and update the intersection count. This must be done - * separately for vertical edges, horizontal edges, and - * other edges. - */ - - if (pPtr[2] == pPtr[0]) { - - /* - * Vertical edge. - */ - - x = pPtr[0]; - if (pPtr[1] >= pPtr[3]) { - y = MIN(pPtr[1], pointPtr[1]); - y = MAX(y, pPtr[3]); - } else { - y = MIN(pPtr[3], pointPtr[1]); - y = MAX(y, pPtr[1]); - } - } else if (pPtr[3] == pPtr[1]) { - - /* - * Horizontal edge. - */ - - y = pPtr[1]; - if (pPtr[0] >= pPtr[2]) { - x = MIN(pPtr[0], pointPtr[0]); - x = MAX(x, pPtr[2]); - if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[0]) - && (pointPtr[0] >= pPtr[2])) { - intersections++; - } - } else { - x = MIN(pPtr[2], pointPtr[0]); - x = MAX(x, pPtr[0]); - if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[2]) - && (pointPtr[0] >= pPtr[0])) { - intersections++; - } - } - } else { - double m1, b1, m2, b2; - int lower; /* Non-zero means point below line. */ - - /* - * The edge is neither horizontal nor vertical. Convert the - * edge to a line equation of the form y = m1*x + b1. Then - * compute a line perpendicular to this edge but passing - * through the point, also in the form y = m2*x + b2. - */ - - m1 = (pPtr[3] - pPtr[1])/(pPtr[2] - pPtr[0]); - b1 = pPtr[1] - m1*pPtr[0]; - m2 = -1.0/m1; - b2 = pointPtr[1] - m2*pointPtr[0]; - x = (b2 - b1)/(m1 - m2); - y = m1*x + b1; - if (pPtr[0] > pPtr[2]) { - if (x > pPtr[0]) { - x = pPtr[0]; - y = pPtr[1]; - } else if (x < pPtr[2]) { - x = pPtr[2]; - y = pPtr[3]; - } - } else { - if (x > pPtr[2]) { - x = pPtr[2]; - y = pPtr[3]; - } else if (x < pPtr[0]) { - x = pPtr[0]; - y = pPtr[1]; - } - } - lower = (m1*pointPtr[0] + b1) > pointPtr[1]; - if (lower && (pointPtr[0] >= MIN(pPtr[0], pPtr[2])) - && (pointPtr[0] < MAX(pPtr[0], pPtr[2]))) { - intersections++; - } - } - - /* - * Compute the distance to the closest point, and see if that - * is the best distance seen so far. - */ - - dist = hypot(pointPtr[0] - x, pointPtr[1] - y); - if (dist < bestDist) { - bestDist = dist; - } - } - - /* - * We've processed all of the points. If the number of intersections - * is odd, the point is inside the polygon. - */ - - if (intersections & 0x1) { - return 0.0; - } - return bestDist; -} - -/* - *-------------------------------------------------------------- - * - * TkPolygonToArea -- - * - * Determine whether a polygon lies entirely inside, entirely - * outside, or overlapping a given rectangular area. - * - * Results: - * -1 is returned if the polygon given by polyPtr and numPoints - * is entirely outside the rectangle given by rectPtr. 0 is - * returned if the polygon overlaps the rectangle, and 1 is - * returned if the polygon is entirely inside the rectangle. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkPolygonToArea(polyPtr, numPoints, rectPtr) - double *polyPtr; /* Points to an array coordinates for - * closed polygon: x0, y0, x1, y1, ... - * The polygon may be self-intersecting. */ - int numPoints; /* Total number of points at *polyPtr. */ - register double *rectPtr; /* Points to coords for rectangle, in the - * order x1, y1, x2, y2. X1 and y1 must - * be lower-left corner. */ -{ - int state; /* State of all edges seen so far (-1 means - * outside, 1 means inside, won't ever be - * 0). */ - int count; - register double *pPtr; - - /* - * Iterate over all of the edges of the polygon and test them - * against the rectangle. Can quit as soon as the state becomes - * "intersecting". - */ - - state = TkLineToArea(polyPtr, polyPtr+2, rectPtr); - if (state == 0) { - return 0; - } - for (pPtr = polyPtr+2, count = numPoints-1; count >= 2; - pPtr += 2, count--) { - if (TkLineToArea(pPtr, pPtr+2, rectPtr) != state) { - return 0; - } - } - - /* - * If all of the edges were inside the rectangle we're done. - * If all of the edges were outside, then the rectangle could - * still intersect the polygon (if it's entirely enclosed). - * Call TkPolygonToPoint to figure this out. - */ - - if (state == 1) { - return 1; - } - if (TkPolygonToPoint(polyPtr, numPoints, rectPtr) == 0.0) { - return 0; - } - return -1; -} - -/* - *-------------------------------------------------------------- - * - * TkOvalToPoint -- - * - * Computes the distance from a given point to a given - * oval, in canvas units. - * - * Results: - * The return value is 0 if the point given by *pointPtr is - * inside the oval. If the point isn't inside the - * oval then the return value is approximately the distance - * from the point to the oval. If the oval is filled, then - * anywhere in the interior is considered "inside"; if - * the oval isn't filled, then "inside" means only the area - * occupied by the outline. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -double -TkOvalToPoint(ovalPtr, width, filled, pointPtr) - double ovalPtr[4]; /* Pointer to array of four coordinates - * (x1, y1, x2, y2) defining oval's bounding - * box. */ - double width; /* Width of outline for oval. */ - int filled; /* Non-zero means oval should be treated as - * filled; zero means only consider outline. */ - double pointPtr[2]; /* Coordinates of point. */ -{ - double xDelta, yDelta, scaledDistance, distToOutline, distToCenter; - double xDiam, yDiam; - - /* - * Compute the distance between the center of the oval and the - * point in question, using a coordinate system where the oval - * has been transformed to a circle with unit radius. - */ - - xDelta = (pointPtr[0] - (ovalPtr[0] + ovalPtr[2])/2.0); - yDelta = (pointPtr[1] - (ovalPtr[1] + ovalPtr[3])/2.0); - distToCenter = hypot(xDelta, yDelta); - scaledDistance = hypot(xDelta / ((ovalPtr[2] + width - ovalPtr[0])/2.0), - yDelta / ((ovalPtr[3] + width - ovalPtr[1])/2.0)); - - - /* - * If the scaled distance is greater than 1 then it means no - * hit. Compute the distance from the point to the edge of - * the circle, then scale this distance back to the original - * coordinate system. - * - * Note: this distance isn't completely accurate. It's only - * an approximation, and it can overestimate the correct - * distance when the oval is eccentric. - */ - - if (scaledDistance > 1.0) { - return (distToCenter/scaledDistance) * (scaledDistance - 1.0); - } - - /* - * Scaled distance less than 1 means the point is inside the - * outer edge of the oval. If this is a filled oval, then we - * have a hit. Otherwise, do the same computation as above - * (scale back to original coordinate system), but also check - * to see if the point is within the width of the outline. - */ - - if (filled) { - return 0.0; - } - if (scaledDistance > 1E-10) { - distToOutline = (distToCenter/scaledDistance) * (1.0 - scaledDistance) - - width; - } else { - /* - * Avoid dividing by a very small number (it could cause an - * arithmetic overflow). This problem occurs if the point is - * very close to the center of the oval. - */ - - xDiam = ovalPtr[2] - ovalPtr[0]; - yDiam = ovalPtr[3] - ovalPtr[1]; - if (xDiam < yDiam) { - distToOutline = (xDiam - width)/2; - } else { - distToOutline = (yDiam - width)/2; - } - } - - if (distToOutline < 0.0) { - return 0.0; - } - return distToOutline; -} - -/* - *-------------------------------------------------------------- - * - * TkOvalToArea -- - * - * Determine whether an oval lies entirely inside, entirely - * outside, or overlapping a given rectangular area. - * - * Results: - * -1 is returned if the oval described by ovalPtr is entirely - * outside the rectangle given by rectPtr. 0 is returned if the - * oval overlaps the rectangle, and 1 is returned if the oval - * is entirely inside the rectangle. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkOvalToArea(ovalPtr, rectPtr) - register double *ovalPtr; /* Points to coordinates definining the - * bounding rectangle for the oval: x1, y1, - * x2, y2. X1 must be less than x2 and y1 - * less than y2. */ - register double *rectPtr; /* Points to coords for rectangle, in the - * order x1, y1, x2, y2. X1 and y1 must - * be lower-left corner. */ -{ - double centerX, centerY, radX, radY, deltaX, deltaY; - - /* - * First, see if oval is entirely inside rectangle or entirely - * outside rectangle. - */ - - if ((rectPtr[0] <= ovalPtr[0]) && (rectPtr[2] >= ovalPtr[2]) - && (rectPtr[1] <= ovalPtr[1]) && (rectPtr[3] >= ovalPtr[3])) { - return 1; - } - if ((rectPtr[2] < ovalPtr[0]) || (rectPtr[0] > ovalPtr[2]) - || (rectPtr[3] < ovalPtr[1]) || (rectPtr[1] > ovalPtr[3])) { - return -1; - } - - /* - * Next, go through the rectangle side by side. For each side - * of the rectangle, find the point on the side that is closest - * to the oval's center, and see if that point is inside the - * oval. If at least one such point is inside the oval, then - * the rectangle intersects the oval. - */ - - centerX = (ovalPtr[0] + ovalPtr[2])/2; - centerY = (ovalPtr[1] + ovalPtr[3])/2; - radX = (ovalPtr[2] - ovalPtr[0])/2; - radY = (ovalPtr[3] - ovalPtr[1])/2; - - deltaY = rectPtr[1] - centerY; - if (deltaY < 0.0) { - deltaY = centerY - rectPtr[3]; - if (deltaY < 0.0) { - deltaY = 0; - } - } - deltaY /= radY; - deltaY *= deltaY; - - /* - * Left side: - */ - - deltaX = (rectPtr[0] - centerX)/radX; - deltaX *= deltaX; - if ((deltaX + deltaY) <= 1.0) { - return 0; - } - - /* - * Right side: - */ - - deltaX = (rectPtr[2] - centerX)/radX; - deltaX *= deltaX; - if ((deltaX + deltaY) <= 1.0) { - return 0; - } - - deltaX = rectPtr[0] - centerX; - if (deltaX < 0.0) { - deltaX = centerX - rectPtr[2]; - if (deltaX < 0.0) { - deltaX = 0; - } - } - deltaX /= radX; - deltaX *= deltaX; - - /* - * Bottom side: - */ - - deltaY = (rectPtr[1] - centerY)/radY; - deltaY *= deltaY; - if ((deltaX + deltaY) < 1.0) { - return 0; - } - - /* - * Top side: - */ - - deltaY = (rectPtr[3] - centerY)/radY; - deltaY *= deltaY; - if ((deltaX + deltaY) < 1.0) { - return 0; - } - - return -1; -} - -/* - *-------------------------------------------------------------- - * - * TkIncludePoint -- - * - * Given a point and a generic canvas item header, expand - * the item's bounding box if needed to include the point. - * - * Results: - * None. - * - * Side effects: - * The boudn. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkIncludePoint(itemPtr, pointPtr) - register Tk_Item *itemPtr; /* Item whose bounding box is - * being calculated. */ - double *pointPtr; /* Address of two doubles giving - * x and y coordinates of point. */ -{ - int tmp; - - tmp = (int) (pointPtr[0] + 0.5); - if (tmp < itemPtr->x1) { - itemPtr->x1 = tmp; - } - if (tmp > itemPtr->x2) { - itemPtr->x2 = tmp; - } - tmp = (int) (pointPtr[1] + 0.5); - if (tmp < itemPtr->y1) { - itemPtr->y1 = tmp; - } - if (tmp > itemPtr->y2) { - itemPtr->y2 = tmp; - } -} - -/* - *-------------------------------------------------------------- - * - * TkBezierScreenPoints -- - * - * Given four control points, create a larger set of XPoints - * for a Bezier spline based on the points. - * - * Results: - * The array at *xPointPtr gets filled in with numSteps XPoints - * corresponding to the Bezier spline defined by the four - * control points. Note: no output point is generated for the - * first input point, but an output point *is* generated for - * the last input point. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkBezierScreenPoints(canvas, control, numSteps, xPointPtr) - Tk_Canvas canvas; /* Canvas in which curve is to be - * drawn. */ - double control[]; /* Array of coordinates for four - * control points: x0, y0, x1, y1, - * ... x3 y3. */ - int numSteps; /* Number of curve points to - * generate. */ - register XPoint *xPointPtr; /* Where to put new points. */ -{ - int i; - double u, u2, u3, t, t2, t3; - - for (i = 1; i <= numSteps; i++, xPointPtr++) { - t = ((double) i)/((double) numSteps); - t2 = t*t; - t3 = t2*t; - u = 1.0 - t; - u2 = u*u; - u3 = u2*u; - Tk_CanvasDrawableCoords(canvas, - (control[0]*u3 + 3.0 * (control[2]*t*u2 + control[4]*t2*u) - + control[6]*t3), - (control[1]*u3 + 3.0 * (control[3]*t*u2 + control[5]*t2*u) - + control[7]*t3), - &xPointPtr->x, &xPointPtr->y); - } -} - -/* - *-------------------------------------------------------------- - * - * TkBezierPoints -- - * - * Given four control points, create a larger set of points - * for a Bezier spline based on the points. - * - * Results: - * The array at *coordPtr gets filled in with 2*numSteps - * coordinates, which correspond to the Bezier spline defined - * by the four control points. Note: no output point is - * generated for the first input point, but an output point - * *is* generated for the last input point. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkBezierPoints(control, numSteps, coordPtr) - double control[]; /* Array of coordinates for four - * control points: x0, y0, x1, y1, - * ... x3 y3. */ - int numSteps; /* Number of curve points to - * generate. */ - register double *coordPtr; /* Where to put new points. */ -{ - int i; - double u, u2, u3, t, t2, t3; - - for (i = 1; i <= numSteps; i++, coordPtr += 2) { - t = ((double) i)/((double) numSteps); - t2 = t*t; - t3 = t2*t; - u = 1.0 - t; - u2 = u*u; - u3 = u2*u; - coordPtr[0] = control[0]*u3 - + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3; - coordPtr[1] = control[1]*u3 - + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3; - } -} - -/* - *-------------------------------------------------------------- - * - * TkMakeBezierCurve -- - * - * Given a set of points, create a new set of points that fit - * parabolic splines to the line segments connecting the original - * points. Produces output points in either of two forms. - * - * Note: in spite of this procedure's name, it does *not* generate - * Bezier curves. Since only three control points are used for - * each curve segment, not four, the curves are actually just - * parabolic. - * - * Results: - * Either or both of the xPoints or dblPoints arrays are filled - * in. The return value is the number of points placed in the - * arrays. Note: if the first and last points are the same, then - * a closed curve is generated. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints) - Tk_Canvas canvas; /* Canvas in which curve is to be - * drawn. */ - double *pointPtr; /* Array of input coordinates: x0, - * y0, x1, y1, etc.. */ - int numPoints; /* Number of points at pointPtr. */ - int numSteps; /* Number of steps to use for each - * spline segments (determines - * smoothness of curve). */ - XPoint xPoints[]; /* Array of XPoints to fill in (e.g. - * for display. NULL means don't - * fill in any XPoints. */ - double dblPoints[]; /* Array of points to fill in as - * doubles, in the form x0, y0, - * x1, y1, .... NULL means don't - * fill in anything in this form. - * Caller must make sure that this - * array has enough space. */ -{ - int closed, outputPoints, i; - int numCoords = numPoints*2; - double control[8]; - - /* - * If the curve is a closed one then generate a special spline - * that spans the last points and the first ones. Otherwise - * just put the first point into the output. - */ - - outputPoints = 0; - if ((pointPtr[0] == pointPtr[numCoords-2]) - && (pointPtr[1] == pointPtr[numCoords-1])) { - closed = 1; - control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; - control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; - control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; - control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; - control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; - control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; - control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; - control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; - if (xPoints != NULL) { - Tk_CanvasDrawableCoords(canvas, control[0], control[1], - &xPoints->x, &xPoints->y); - TkBezierScreenPoints(canvas, control, numSteps, xPoints+1); - xPoints += numSteps+1; - } - if (dblPoints != NULL) { - dblPoints[0] = control[0]; - dblPoints[1] = control[1]; - TkBezierPoints(control, numSteps, dblPoints+2); - dblPoints += 2*(numSteps+1); - } - outputPoints += numSteps+1; - } else { - closed = 0; - if (xPoints != NULL) { - Tk_CanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1], - &xPoints->x, &xPoints->y); - xPoints += 1; - } - if (dblPoints != NULL) { - dblPoints[0] = pointPtr[0]; - dblPoints[1] = pointPtr[1]; - dblPoints += 2; - } - outputPoints += 1; - } - - for (i = 2; i < numPoints; i++, pointPtr += 2) { - /* - * Set up the first two control points. This is done - * differently for the first spline of an open curve - * than for other cases. - */ - - if ((i == 2) && !closed) { - control[0] = pointPtr[0]; - control[1] = pointPtr[1]; - control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2]; - control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3]; - } else { - control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; - control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; - control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2]; - control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3]; - } - - /* - * Set up the last two control points. This is done - * differently for the last spline of an open curve - * than for other cases. - */ - - if ((i == (numPoints-1)) && !closed) { - control[4] = .667*pointPtr[2] + .333*pointPtr[4]; - control[5] = .667*pointPtr[3] + .333*pointPtr[5]; - control[6] = pointPtr[4]; - control[7] = pointPtr[5]; - } else { - control[4] = .833*pointPtr[2] + .167*pointPtr[4]; - control[5] = .833*pointPtr[3] + .167*pointPtr[5]; - control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4]; - control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5]; - } - - /* - * If the first two points coincide, or if the last - * two points coincide, then generate a single - * straight-line segment by outputting the last control - * point. - */ - - if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3])) - || ((pointPtr[2] == pointPtr[4]) - && (pointPtr[3] == pointPtr[5]))) { - if (xPoints != NULL) { - Tk_CanvasDrawableCoords(canvas, control[6], control[7], - &xPoints[0].x, &xPoints[0].y); - xPoints++; - } - if (dblPoints != NULL) { - dblPoints[0] = control[6]; - dblPoints[1] = control[7]; - dblPoints += 2; - } - outputPoints += 1; - continue; - } - - /* - * Generate a Bezier spline using the control points. - */ - - - if (xPoints != NULL) { - TkBezierScreenPoints(canvas, control, numSteps, xPoints); - xPoints += numSteps; - } - if (dblPoints != NULL) { - TkBezierPoints(control, numSteps, dblPoints); - dblPoints += 2*numSteps; - } - outputPoints += numSteps; - } - return outputPoints; -} - -/* - *-------------------------------------------------------------- - * - * TkMakeBezierPostscript -- - * - * This procedure generates Postscript commands that create - * a path corresponding to a given Bezier curve. - * - * Results: - * None. Postscript commands to generate the path are appended - * to interp->result. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkMakeBezierPostscript(interp, canvas, pointPtr, numPoints) - Tcl_Interp *interp; /* Interpreter in whose result the - * Postscript is to be stored. */ - Tk_Canvas canvas; /* Canvas widget for which the - * Postscript is being generated. */ - double *pointPtr; /* Array of input coordinates: x0, - * y0, x1, y1, etc.. */ - int numPoints; /* Number of points at pointPtr. */ -{ - int closed, i; - int numCoords = numPoints*2; - double control[8]; - char buffer[200]; - - /* - * If the curve is a closed one then generate a special spline - * that spans the last points and the first ones. Otherwise - * just put the first point into the path. - */ - - if ((pointPtr[0] == pointPtr[numCoords-2]) - && (pointPtr[1] == pointPtr[numCoords-1])) { - closed = 1; - control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; - control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; - control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; - control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; - control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; - control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; - control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; - control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; - sprintf(buffer, "%.15g %.15g moveto\n%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", - control[0], Tk_CanvasPsY(canvas, control[1]), - control[2], Tk_CanvasPsY(canvas, control[3]), - control[4], Tk_CanvasPsY(canvas, control[5]), - control[6], Tk_CanvasPsY(canvas, control[7])); - } else { - closed = 0; - control[6] = pointPtr[0]; - control[7] = pointPtr[1]; - sprintf(buffer, "%.15g %.15g moveto\n", - control[6], Tk_CanvasPsY(canvas, control[7])); - } - Tcl_AppendResult(interp, buffer, (char *) NULL); - - /* - * Cycle through all the remaining points in the curve, generating - * a curve section for each vertex in the linear path. - */ - - for (i = numPoints-2, pointPtr += 2; i > 0; i--, pointPtr += 2) { - control[2] = 0.333*control[6] + 0.667*pointPtr[0]; - control[3] = 0.333*control[7] + 0.667*pointPtr[1]; - - /* - * Set up the last two control points. This is done - * differently for the last spline of an open curve - * than for other cases. - */ - - if ((i == 1) && !closed) { - control[6] = pointPtr[2]; - control[7] = pointPtr[3]; - } else { - control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; - control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; - } - control[4] = 0.333*control[6] + 0.667*pointPtr[0]; - control[5] = 0.333*control[7] + 0.667*pointPtr[1]; - - sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", - control[2], Tk_CanvasPsY(canvas, control[3]), - control[4], Tk_CanvasPsY(canvas, control[5]), - control[6], Tk_CanvasPsY(canvas, control[7])); - Tcl_AppendResult(interp, buffer, (char *) NULL); - } -} - -/* - *-------------------------------------------------------------- - * - * TkGetMiterPoints -- - * - * Given three points forming an angle, compute the - * coordinates of the inside and outside points of - * the mitered corner formed by a line of a given - * width at that angle. - * - * Results: - * If the angle formed by the three points is less than - * 11 degrees then 0 is returned and m1 and m2 aren't - * modified. Otherwise 1 is returned and the points at - * m1 and m2 are filled in with the positions of the points - * of the mitered corner. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkGetMiterPoints(p1, p2, p3, width, m1, m2) - double p1[]; /* Points to x- and y-coordinates of point - * before vertex. */ - double p2[]; /* Points to x- and y-coordinates of vertex - * for mitered joint. */ - double p3[]; /* Points to x- and y-coordinates of point - * after vertex. */ - double width; /* Width of line. */ - double m1[]; /* Points to place to put "left" vertex - * point (see as you face from p1 to p2). */ - double m2[]; /* Points to place to put "right" vertex - * point. */ -{ - double theta1; /* Angle of segment p2-p1. */ - double theta2; /* Angle of segment p2-p3. */ - double theta; /* Angle between line segments (angle - * of joint). */ - double theta3; /* Angle that bisects theta1 and - * theta2 and points to m1. */ - double dist; /* Distance of miter points from p2. */ - double deltaX, deltaY; /* X and y offsets cooresponding to - * dist (fudge factors for bounding - * box). */ - double p1x, p1y, p2x, p2y, p3x, p3y; - static double elevenDegrees = (11.0*2.0*PI)/360.0; - - /* - * Round the coordinates to integers to mimic what happens when the - * line segments are displayed; without this code, the bounding box - * of a mitered line can be miscomputed greatly. - */ - - p1x = floor(p1[0]+0.5); - p1y = floor(p1[1]+0.5); - p2x = floor(p2[0]+0.5); - p2y = floor(p2[1]+0.5); - p3x = floor(p3[0]+0.5); - p3y = floor(p3[1]+0.5); - - if (p2y == p1y) { - theta1 = (p2x < p1x) ? 0 : PI; - } else if (p2x == p1x) { - theta1 = (p2y < p1y) ? PI/2.0 : -PI/2.0; - } else { - theta1 = atan2(p1y - p2y, p1x - p2x); - } - if (p3y == p2y) { - theta2 = (p3x > p2x) ? 0 : PI; - } else if (p3x == p2x) { - theta2 = (p3y > p2y) ? PI/2.0 : -PI/2.0; - } else { - theta2 = atan2(p3y - p2y, p3x - p2x); - } - theta = theta1 - theta2; - if (theta > PI) { - theta -= 2*PI; - } else if (theta < -PI) { - theta += 2*PI; - } - if ((theta < elevenDegrees) && (theta > -elevenDegrees)) { - return 0; - } - dist = 0.5*width/sin(0.5*theta); - if (dist < 0.0) { - dist = -dist; - } - - /* - * Compute theta3 (make sure that it points to the left when - * looking from p1 to p2). - */ - - theta3 = (theta1 + theta2)/2.0; - if (sin(theta3 - (theta1 + PI)) < 0.0) { - theta3 += PI; - } - deltaX = dist*cos(theta3); - m1[0] = p2x + deltaX; - m2[0] = p2x - deltaX; - deltaY = dist*sin(theta3); - m1[1] = p2y + deltaY; - m2[1] = p2y - deltaY; - return 1; -} - -/* - *-------------------------------------------------------------- - * - * TkGetButtPoints -- - * - * Given two points forming a line segment, compute the - * coordinates of two endpoints of a rectangle formed by - * bloating the line segment until it is width units wide. - * - * Results: - * There is no return value. M1 and m2 are filled in to - * correspond to m1 and m2 in the diagram below: - * - * ----------------* m1 - * | - * p1 *---------------* p2 - * | - * ----------------* m2 - * - * M1 and m2 will be W units apart, with p2 centered between - * them and m1-m2 perpendicular to p1-p2. However, if - * "project" is true then m1 and m2 will be as follows: - * - * -------------------* m1 - * p2 | - * p1 *---------------* | - * | - * -------------------* m2 - * - * In this case p2 will be width/2 units from the segment m1-m2. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkGetButtPoints(p1, p2, width, project, m1, m2) - double p1[]; /* Points to x- and y-coordinates of point - * before vertex. */ - double p2[]; /* Points to x- and y-coordinates of vertex - * for mitered joint. */ - double width; /* Width of line. */ - int project; /* Non-zero means project p2 by an additional - * width/2 before computing m1 and m2. */ - double m1[]; /* Points to place to put "left" result - * point, as you face from p1 to p2. */ - double m2[]; /* Points to place to put "right" result - * point. */ -{ - double length; /* Length of p1-p2 segment. */ - double deltaX, deltaY; /* Increments in coords. */ - - width *= 0.5; - length = hypot(p2[0] - p1[0], p2[1] - p1[1]); - if (length == 0.0) { - m1[0] = m2[0] = p2[0]; - m1[1] = m2[1] = p2[1]; - } else { - deltaX = -width * (p2[1] - p1[1]) / length; - deltaY = width * (p2[0] - p1[0]) / length; - m1[0] = p2[0] + deltaX; - m2[0] = p2[0] - deltaX; - m1[1] = p2[1] + deltaY; - m2[1] = p2[1] - deltaY; - if (project) { - m1[0] += deltaY; - m2[0] += deltaY; - m1[1] -= deltaX; - m2[1] -= deltaX; - } - } -} diff --git a/generic/tkUtil.c b/generic/tkUtil.c deleted file mode 100644 index 547fd16..0000000 --- a/generic/tkUtil.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * tkUtil.c -- - * - * This file contains miscellaneous utility procedures that - * are used by the rest of Tk, such as a procedure for drawing - * a focus highlight. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkUtil.c,v 1.2 1998/09/14 18:23:20 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - *---------------------------------------------------------------------- - * - * TkDrawInsetFocusHighlight -- - * - * This procedure draws a rectangular ring around the outside of - * a widget to indicate that it has received the input focus. It - * takes an additional padding argument that specifies how much - * padding is present outside th widget. - * - * Results: - * None. - * - * Side effects: - * A rectangle "width" pixels wide is drawn in "drawable", - * corresponding to the outer area of "tkwin". - * - *---------------------------------------------------------------------- - */ - -void -TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, padding) - Tk_Window tkwin; /* Window whose focus highlight ring is - * to be drawn. */ - GC gc; /* Graphics context to use for drawing - * the highlight ring. */ - int width; /* Width of the highlight ring, in pixels. */ - Drawable drawable; /* Where to draw the ring (typically a - * pixmap for double buffering). */ - int padding; /* Width of padding outside of widget. */ -{ - XRectangle rects[4]; - - /* - * On the Macintosh the highlight ring needs to be "padded" - * out by one pixel. Unfortunantly, none of the Tk widgets - * had a notion of padding between the focus ring and the - * widget. So we add this padding here. This introduces - * two things to worry about: - * - * 1) The widget must draw the background color covering - * the focus ring area before calling Tk_DrawFocus. - * 2) It is impossible to draw a focus ring of width 1. - * (For the Macintosh Look & Feel use width of 3) - */ -#ifdef MAC_TCL - width--; -#endif - - rects[0].x = padding; - rects[0].y = padding; - rects[0].width = Tk_Width(tkwin) - (2 * padding); - rects[0].height = width; - rects[1].x = padding; - rects[1].y = Tk_Height(tkwin) - width - padding; - rects[1].width = Tk_Width(tkwin) - (2 * padding); - rects[1].height = width; - rects[2].x = padding; - rects[2].y = width + padding; - rects[2].width = width; - rects[2].height = Tk_Height(tkwin) - 2*width - 2*padding; - rects[3].x = Tk_Width(tkwin) - width - padding; - rects[3].y = rects[2].y; - rects[3].width = width; - rects[3].height = rects[2].height; - XFillRectangles(Tk_Display(tkwin), drawable, gc, rects, 4); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DrawFocusHighlight -- - * - * This procedure draws a rectangular ring around the outside of - * a widget to indicate that it has received the input focus. - * - * Results: - * None. - * - * Side effects: - * A rectangle "width" pixels wide is drawn in "drawable", - * corresponding to the outer area of "tkwin". - * - *---------------------------------------------------------------------- - */ - -void -Tk_DrawFocusHighlight(tkwin, gc, width, drawable) - Tk_Window tkwin; /* Window whose focus highlight ring is - * to be drawn. */ - GC gc; /* Graphics context to use for drawing - * the highlight ring. */ - int width; /* Width of the highlight ring, in pixels. */ - Drawable drawable; /* Where to draw the ring (typically a - * pixmap for double buffering). */ -{ - TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, 0); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetScrollInfo -- - * - * This procedure is invoked to parse "xview" and "yview" - * scrolling commands for widgets using the new scrolling - * command syntax ("moveto" or "scroll" options). - * - * Results: - * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES, - * TK_SCROLL_UNITS, or TK_SCROLL_ERROR. This indicates whether - * the command was successfully parsed and what form the command - * took. If TK_SCROLL_MOVETO, *dblPtr is filled in with the - * desired position; if TK_SCROLL_PAGES or TK_SCROLL_UNITS, - * *intPtr is filled in with the number of lines to move (may be - * negative); if TK_SCROLL_ERROR, interp->result contains an - * error message. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_GetScrollInfo(interp, argc, argv, dblPtr, intPtr) - Tcl_Interp *interp; /* Used for error reporting. */ - int argc; /* # arguments for command. */ - char **argv; /* Arguments for command. */ - double *dblPtr; /* Filled in with argument "moveto" - * option, if any. */ - int *intPtr; /* Filled in with number of pages - * or lines to scroll, if any. */ -{ - int c; - size_t length; - - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'm') && (strncmp(argv[2], "moveto", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ", argv[1], " moveto fraction\"", - (char *) NULL); - return TK_SCROLL_ERROR; - } - if (Tcl_GetDouble(interp, argv[3], dblPtr) != TCL_OK) { - return TK_SCROLL_ERROR; - } - return TK_SCROLL_MOVETO; - } else if ((c == 's') - && (strncmp(argv[2], "scroll", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ", argv[1], " scroll number units|pages\"", - (char *) NULL); - return TK_SCROLL_ERROR; - } - if (Tcl_GetInt(interp, argv[3], intPtr) != TCL_OK) { - return TK_SCROLL_ERROR; - } - length = strlen(argv[4]); - c = argv[4][0]; - if ((c == 'p') && (strncmp(argv[4], "pages", length) == 0)) { - return TK_SCROLL_PAGES; - } else if ((c == 'u') - && (strncmp(argv[4], "units", length) == 0)) { - return TK_SCROLL_UNITS; - } else { - Tcl_AppendResult(interp, "bad argument \"", argv[4], - "\": must be units or pages", (char *) NULL); - return TK_SCROLL_ERROR; - } - } - Tcl_AppendResult(interp, "unknown option \"", argv[2], - "\": must be moveto or scroll", (char *) NULL); - return TK_SCROLL_ERROR; -} - -/* - *--------------------------------------------------------------------------- - * - * TkComputeAnchor -- - * - * Determine where to place a rectangle so that it will be properly - * anchored with respect to the given window. Used by widgets - * to align a box of text inside a window. When anchoring with - * respect to one of the sides, the rectangle be placed inside of - * the internal border of the window. - * - * Results: - * *xPtr and *yPtr set to the upper-left corner of the rectangle - * anchored in the window. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ -void -TkComputeAnchor(anchor, tkwin, padX, padY, innerWidth, innerHeight, xPtr, yPtr) - Tk_Anchor anchor; /* Desired anchor. */ - Tk_Window tkwin; /* Anchored with respect to this window. */ - int padX, padY; /* Use this extra padding inside window, in - * addition to the internal border. */ - int innerWidth, innerHeight;/* Size of rectangle to anchor in window. */ - int *xPtr, *yPtr; /* Returns upper-left corner of anchored - * rectangle. */ -{ - switch (anchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_W: - case TK_ANCHOR_SW: - *xPtr = Tk_InternalBorderWidth(tkwin) + padX; - break; - - case TK_ANCHOR_N: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_S: - *xPtr = (Tk_Width(tkwin) - innerWidth) / 2; - break; - - default: - *xPtr = Tk_Width(tkwin) - (Tk_InternalBorderWidth(tkwin) + padX) - - innerWidth; - break; - } - - switch (anchor) { - case TK_ANCHOR_NW: - case TK_ANCHOR_N: - case TK_ANCHOR_NE: - *yPtr = Tk_InternalBorderWidth(tkwin) + padY; - break; - - case TK_ANCHOR_W: - case TK_ANCHOR_CENTER: - case TK_ANCHOR_E: - *yPtr = (Tk_Height(tkwin) - innerHeight) / 2; - break; - - default: - *yPtr = Tk_Height(tkwin) - Tk_InternalBorderWidth(tkwin) - padY - - innerHeight; - break; - } -} - -/* - *--------------------------------------------------------------------------- - * - * TkFindStateString -- - * - * Given a lookup table, map a number to a string in the table. - * - * Results: - * If numKey was equal to the numeric key of one of the elements - * in the table, returns the string key of that element. - * Returns NULL if numKey was not equal to any of the numeric keys - * in the table. - * - * Side effects. - * None. - * - *--------------------------------------------------------------------------- - */ - -char * -TkFindStateString(mapPtr, numKey) - CONST TkStateMap *mapPtr; /* The state table. */ - int numKey; /* The key to try to find in the table. */ -{ - for ( ; mapPtr->strKey != NULL; mapPtr++) { - if (numKey == mapPtr->numKey) { - return mapPtr->strKey; - } - } - return NULL; -} - -/* - *--------------------------------------------------------------------------- - * - * TkFindStateNum -- - * - * Given a lookup table, map a string to a number in the table. - * - * Results: - * If strKey was equal to the string keys of one of the elements - * in the table, returns the numeric key of that element. - * Returns the numKey associated with the last element (the NULL - * string one) in the table if strKey was not equal to any of the - * string keys in the table. In that case, an error message is - * also left in interp->result (if interp is not NULL). - * - * Side effects. - * None. - * - *--------------------------------------------------------------------------- - */ - -int -TkFindStateNum(interp, field, mapPtr, strKey) - Tcl_Interp *interp; /* Interp for error reporting. */ - CONST char *field; /* String to use when constructing error. */ - CONST TkStateMap *mapPtr; /* Lookup table. */ - CONST char *strKey; /* String to try to find in lookup table. */ -{ - CONST TkStateMap *mPtr; - - if (mapPtr->strKey == NULL) { - panic("TkFindStateNum: no choices in lookup table"); - } - - for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) { - if (strcmp(strKey, mPtr->strKey) == 0) { - return mPtr->numKey; - } - } - if (interp != NULL) { - mPtr = mapPtr; - Tcl_AppendResult(interp, "bad ", field, " value \"", strKey, - "\": must be ", mPtr->strKey, (char *) NULL); - for (mPtr++; mPtr->strKey != NULL; mPtr++) { - Tcl_AppendResult(interp, ", ", mPtr->strKey, (char *) NULL); - } - } - return mPtr->numKey; -} diff --git a/generic/tkVisual.c b/generic/tkVisual.c deleted file mode 100644 index 96a2979..0000000 --- a/generic/tkVisual.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * tkVisual.c -- - * - * This file contains library procedures for allocating and - * freeing visuals and colormaps. This code is based on a - * prototype implementation by Paul Mackerras. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkVisual.c,v 1.2 1998/09/14 18:23:20 stanton Exp $ - */ - -#include "tkInt.h" -#include "tkPort.h" - -/* - * The table below maps from symbolic names for visual classes - * to the associated X class symbols. - */ - -typedef struct VisualDictionary { - char *name; /* Textual name of class. */ - int minLength; /* Minimum # characters that must be - * specified for an unambiguous match. */ - int class; /* X symbol for class. */ -} VisualDictionary; -static VisualDictionary visualNames[] = { - {"best", 1, 0}, - {"directcolor", 2, DirectColor}, - {"grayscale", 1, GrayScale}, - {"greyscale", 1, GrayScale}, - {"pseudocolor", 1, PseudoColor}, - {"staticcolor", 7, StaticColor}, - {"staticgray", 7, StaticGray}, - {"staticgrey", 7, StaticGray}, - {"truecolor", 1, TrueColor}, - {NULL, 0, 0}, -}; - -/* - * One of the following structures exists for each distinct non-default - * colormap allocated for a display by Tk_GetColormap. - */ - -struct TkColormap { - Colormap colormap; /* X's identifier for the colormap. */ - Visual *visual; /* Visual for which colormap was - * allocated. */ - int refCount; /* How many uses of the colormap are still - * outstanding (calls to Tk_GetColormap - * minus calls to Tk_FreeColormap). */ - int shareable; /* 0 means this colormap was allocated by - * a call to Tk_GetColormap with "new", - * implying that the window wants it all - * for itself. 1 means that the colormap - * was allocated as a default for a particular - * visual, so it can be shared. */ - struct TkColormap *nextPtr; /* Next in list of colormaps for this display, - * or NULL for end of list. */ -}; - -/* - *---------------------------------------------------------------------- - * - * Tk_GetVisual -- - * - * Given a string identifying a particular kind of visual, this - * procedure returns a visual and depth that matches the specification. - * - * Results: - * The return value is normally a pointer to a visual. If an - * error occurred in looking up the visual, NULL is returned and - * an error message is left in interp->result. The depth of the - * visual is returned to *depthPtr under normal returns. If - * colormapPtr is non-NULL, then this procedure also finds a - * suitable colormap for use with the visual in tkwin, and it - * returns that colormap in *colormapPtr unless an error occurs. - * - * Side effects: - * A new colormap may be allocated. - * - *---------------------------------------------------------------------- - */ - -Visual * -Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr) - Tcl_Interp *interp; /* Interpreter to use for error - * reporting. */ - Tk_Window tkwin; /* Window in which visual will be - * used. */ - char *string; /* String describing visual. See - * manual entry for details. */ - int *depthPtr; /* The depth of the returned visual - * is stored here. */ - Colormap *colormapPtr; /* If non-NULL, then a suitable - * colormap for visual is placed here. - * This colormap must eventually be - * freed by calling Tk_FreeColormap. */ -{ - Tk_Window tkwin2; - XVisualInfo template, *visInfoList, *bestPtr; - long mask; - Visual *visual; - int length, c, numVisuals, prio, bestPrio, i; - char *p; - VisualDictionary *dictPtr; - TkColormap *cmapPtr; - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - - /* - * Parse string and set up a template for use in searching for - * an appropriate visual. - */ - - c = string[0]; - if (c == '.') { - /* - * The string must be a window name. If the window is on the - * same screen as tkwin, then just use its visual. Otherwise - * use the information about the visual as a template for the - * search. - */ - - tkwin2 = Tk_NameToWindow(interp, string, tkwin); - if (tkwin2 == NULL) { - return NULL; - } - visual = Tk_Visual(tkwin2); - if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) { - *depthPtr = Tk_Depth(tkwin2); - if (colormapPtr != NULL) { - /* - * Use the colormap from the other window too (but be sure - * to increment its reference count if it's one of the ones - * allocated here). - */ - - *colormapPtr = Tk_Colormap(tkwin2); - for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL; - cmapPtr = cmapPtr->nextPtr) { - if (cmapPtr->colormap == *colormapPtr) { - cmapPtr->refCount += 1; - break; - } - } - } - return visual; - } - template.depth = Tk_Depth(tkwin2); - template.class = visual->class; - template.red_mask = visual->red_mask; - template.green_mask = visual->green_mask; - template.blue_mask = visual->blue_mask; - template.colormap_size = visual->map_entries; - template.bits_per_rgb = visual->bits_per_rgb; - mask = VisualDepthMask|VisualClassMask|VisualRedMaskMask - |VisualGreenMaskMask|VisualBlueMaskMask|VisualColormapSizeMask - |VisualBitsPerRGBMask; - } else if ((c == 0) || ((c == 'd') && (string[1] != 0) - && (strncmp(string, "default", strlen(string)) == 0))) { - /* - * Use the default visual for the window's screen. - */ - - if (colormapPtr != NULL) { - *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin)); - } - *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin)); - return DefaultVisualOfScreen(Tk_Screen(tkwin)); - } else if (isdigit(UCHAR(c))) { - int visualId; - - /* - * This is a visual ID. - */ - - if (Tcl_GetInt(interp, string, &visualId) == TCL_ERROR) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad X identifier for visual: ", - string, "\"", (char *) NULL); - return NULL; - } - template.visualid = visualId; - mask = VisualIDMask; - } else { - /* - * Parse the string into a class name (or "best") optionally - * followed by whitespace and a depth. - */ - - for (p = string; *p != 0; p++) { - if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) { - break; - } - } - length = p - string; - template.class = -1; - for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) { - if ((dictPtr->name[0] == c) && (length >= dictPtr->minLength) - && (strncmp(string, dictPtr->name, - (size_t) length) == 0)) { - template.class = dictPtr->class; - break; - } - } - if (template.class == -1) { - Tcl_AppendResult(interp, "unknown or ambiguous visual name \"", - string, "\": class must be ", (char *) NULL); - for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) { - Tcl_AppendResult(interp, dictPtr->name, ", ", (char *) NULL); - } - Tcl_AppendResult(interp, "or default", (char *) NULL); - return NULL; - } - while (isspace(UCHAR(*p))) { - p++; - } - if (*p == 0) { - template.depth = 10000; - } else { - if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) { - return NULL; - } - } - if (c == 'b') { - mask = 0; - } else { - mask = VisualClassMask; - } - } - - /* - * Find all visuals that match the template we've just created, - * and return an error if there are none that match. - */ - - template.screen = Tk_ScreenNumber(tkwin); - mask |= VisualScreenMask; - visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template, - &numVisuals); - if (visInfoList == NULL) { - interp->result = "couldn't find an appropriate visual"; - return NULL; - } - - /* - * Search through the visuals that were returned to find the best - * one. The choice is based on the following criteria, in decreasing - * order of importance: - * - * 1. Depth: choose a visual with exactly the desired depth, - * else one with more bits than requested but as few bits - * as possible, else one with fewer bits but as many as - * possible. - * 2. Class: some visual classes are more desirable than others; - * pick the visual with the most desirable class. - * 3. Default: the default visual for the screen gets preference - * over other visuals, all else being equal. - */ - - bestPrio = 0; - bestPtr = NULL; - for (i = 0; i < numVisuals; i++) { - switch (visInfoList[i].class) { - case DirectColor: prio = 5; break; - case GrayScale: prio = 1; break; - case PseudoColor: prio = 7; break; - case StaticColor: prio = 3; break; - case StaticGray: prio = 1; break; - case TrueColor: prio = 5; break; - default: prio = 0; break; - } - if (visInfoList[i].visual - == DefaultVisualOfScreen(Tk_Screen(tkwin))) { - prio++; - } - if (bestPtr == NULL) { - goto newBest; - } - if (visInfoList[i].depth < bestPtr->depth) { - if (visInfoList[i].depth >= template.depth) { - goto newBest; - } - } else if (visInfoList[i].depth > bestPtr->depth) { - if (bestPtr->depth < template.depth) { - goto newBest; - } - } else { - if (prio > bestPrio) { - goto newBest; - } - } - continue; - - newBest: - bestPtr = &visInfoList[i]; - bestPrio = prio; - } - *depthPtr = bestPtr->depth; - visual = bestPtr->visual; - XFree((char *) visInfoList); - - /* - * If we need to find a colormap for this visual, do it now. - * If the visual is the default visual for the screen, then - * use the default colormap. Otherwise search for an existing - * colormap that's shareable. If all else fails, create a new - * colormap. - */ - - if (colormapPtr != NULL) { - if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) { - *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin)); - } else { - for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL; - cmapPtr = cmapPtr->nextPtr) { - if (cmapPtr->shareable && (cmapPtr->visual == visual)) { - *colormapPtr = cmapPtr->colormap; - cmapPtr->refCount += 1; - goto done; - } - } - cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap)); - cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin), - RootWindowOfScreen(Tk_Screen(tkwin)), visual, - AllocNone); - cmapPtr->visual = visual; - cmapPtr->refCount = 1; - cmapPtr->shareable = 1; - cmapPtr->nextPtr = dispPtr->cmapPtr; - dispPtr->cmapPtr = cmapPtr; - *colormapPtr = cmapPtr->colormap; - } - } - - done: - return visual; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetColormap -- - * - * Given a string identifying a colormap, this procedure finds - * an appropriate colormap. - * - * Results: - * The return value is normally the X resource identifier for the - * colormap. If an error occurs, None is returned and an error - * message is placed in interp->result. - * - * Side effects: - * A reference count is incremented for the colormap, so - * Tk_FreeColormap must eventually be called exactly once for - * each call to Tk_GetColormap. - * - *---------------------------------------------------------------------- - */ - -Colormap -Tk_GetColormap(interp, tkwin, string) - Tcl_Interp *interp; /* Interpreter to use for error - * reporting. */ - Tk_Window tkwin; /* Window where colormap will be - * used. */ - char *string; /* String that identifies colormap: - * either "new" or the name of - * another window. */ -{ - Colormap colormap; - TkColormap *cmapPtr; - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - Tk_Window other; - - /* - * Allocate a new colormap, if that's what is wanted. - */ - - if (strcmp(string, "new") == 0) { - cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap)); - cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin), - RootWindowOfScreen(Tk_Screen(tkwin)), Tk_Visual(tkwin), - AllocNone); - cmapPtr->visual = Tk_Visual(tkwin); - cmapPtr->refCount = 1; - cmapPtr->shareable = 0; - cmapPtr->nextPtr = dispPtr->cmapPtr; - dispPtr->cmapPtr = cmapPtr; - return cmapPtr->colormap; - } - - /* - * Use a colormap from an existing window. It must have the same - * visual as tkwin (which means, among other things, that the - * other window must be on the same screen). - */ - - other = Tk_NameToWindow(interp, string, tkwin); - if (other == NULL) { - return None; - } - if (Tk_Screen(other) != Tk_Screen(tkwin)) { - Tcl_AppendResult(interp, "can't use colormap for ", string, - ": not on same screen", (char *) NULL); - return None; - } - if (Tk_Visual(other) != Tk_Visual(tkwin)) { - Tcl_AppendResult(interp, "can't use colormap for ", string, - ": incompatible visuals", (char *) NULL); - return None; - } - colormap = Tk_Colormap(other); - - /* - * If the colormap was a special one allocated by code in this file, - * increment its reference count. - */ - - for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL; - cmapPtr = cmapPtr->nextPtr) { - if (cmapPtr->colormap == colormap) { - cmapPtr->refCount += 1; - } - } - return colormap; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_FreeColormap -- - * - * This procedure is called to release a colormap that was - * previously allocated by Tk_GetColormap. - * - * Results: - * None. - * - * Side effects: - * The colormap's reference count is decremented. If this was the - * last reference to the colormap, then the colormap is freed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_FreeColormap(display, colormap) - Display *display; /* Display for which colormap was - * allocated. */ - Colormap colormap; /* Colormap that is no longer needed. - * Must have been returned by previous - * call to Tk_GetColormap, or - * preserved by a previous call to - * Tk_PreserveColormap. */ -{ - TkDisplay *dispPtr; - TkColormap *cmapPtr, *prevPtr; - - /* - * Find Tk's information about the display, then see if this - * colormap is a non-default one (if it's a default one, there - * won't be an entry for it in the display's list). - */ - - dispPtr = TkGetDisplay(display); - if (dispPtr == NULL) { - panic("unknown display passed to Tk_FreeColormap"); - } - for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL; - prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) { - if (cmapPtr->colormap == colormap) { - cmapPtr->refCount -= 1; - if (cmapPtr->refCount == 0) { - XFreeColormap(display, colormap); - if (prevPtr == NULL) { - dispPtr->cmapPtr = cmapPtr->nextPtr; - } else { - prevPtr->nextPtr = cmapPtr->nextPtr; - } - ckfree((char *) cmapPtr); - } - return; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_PreserveColormap -- - * - * This procedure is called to indicate to Tk that the specified - * colormap is being referenced from another location and should - * not be freed until all extra references are eliminated. The - * colormap must have been returned by Tk_GetColormap. - * - * Results: - * None. - * - * Side effects: - * The colormap's reference count is incremented, so - * Tk_FreeColormap must eventually be called exactly once for - * each call to Tk_PreserveColormap. - * - *---------------------------------------------------------------------- - */ - -void -Tk_PreserveColormap(display, colormap) - Display *display; /* Display for which colormap was - * allocated. */ - Colormap colormap; /* Colormap that should be - * preserved. */ -{ - TkDisplay *dispPtr; - TkColormap *cmapPtr; - - /* - * Find Tk's information about the display, then see if this - * colormap is a non-default one (if it's a default one, there - * won't be an entry for it in the display's list). - */ - - dispPtr = TkGetDisplay(display); - if (dispPtr == NULL) { - panic("unknown display passed to Tk_PreserveColormap"); - } - for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL; - cmapPtr = cmapPtr->nextPtr) { - if (cmapPtr->colormap == colormap) { - cmapPtr->refCount += 1; - return; - } - } -} diff --git a/generic/tkWindow.c b/generic/tkWindow.c deleted file mode 100644 index 6b294e4..0000000 --- a/generic/tkWindow.c +++ /dev/null @@ -1,2836 +0,0 @@ -/* - * tkWindow.c -- - * - * This file provides basic window-manipulation procedures, - * which are equivalent to procedures in Xlib (and even - * invoke them) but also maintain the local Tk_Window - * structure. - * - * Copyright (c) 1989-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkWindow.c,v 1.3 1998/09/14 18:23:20 stanton Exp $ - */ - -#include "tkPort.h" -#include "tkInt.h" - -/* - * Count of number of main windows currently open in this process. - */ - -static int numMainWindows; - -/* - * First in list of all main windows managed by this process. - */ - -TkMainInfo *tkMainWindowList = NULL; - -/* - * List of all displays currently in use. - */ - -TkDisplay *tkDisplayList = NULL; - -/* - * Have statics in this module been initialized? - */ - -static int initialized = 0; - -/* - * The variables below hold several uid's that are used in many places - * in the toolkit. - */ - -Tk_Uid tkDisabledUid = NULL; -Tk_Uid tkActiveUid = NULL; -Tk_Uid tkNormalUid = NULL; - -/* - * Default values for "changes" and "atts" fields of TkWindows. Note - * that Tk always requests all events for all windows, except StructureNotify - * events on internal windows: these events are generated internally. - */ - -static XWindowChanges defChanges = { - 0, 0, 1, 1, 0, 0, Above -}; -#define ALL_EVENTS_MASK \ - KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \ - EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \ - VisibilityChangeMask|PropertyChangeMask|ColormapChangeMask -static XSetWindowAttributes defAtts= { - None, /* background_pixmap */ - 0, /* background_pixel */ - CopyFromParent, /* border_pixmap */ - 0, /* border_pixel */ - NorthWestGravity, /* bit_gravity */ - NorthWestGravity, /* win_gravity */ - NotUseful, /* backing_store */ - (unsigned) ~0, /* backing_planes */ - 0, /* backing_pixel */ - False, /* save_under */ - ALL_EVENTS_MASK, /* event_mask */ - 0, /* do_not_propagate_mask */ - False, /* override_redirect */ - CopyFromParent, /* colormap */ - None /* cursor */ -}; - -/* - * The following structure defines all of the commands supported by - * Tk, and the C procedures that execute them. - */ - -typedef struct { - char *name; /* Name of command. */ - Tcl_CmdProc *cmdProc; /* Command's string-based procedure. */ - Tcl_ObjCmdProc *objProc; /* Command's object-based procedure. */ - int isSafe; /* If !0, this command will be exposed in - * a safe interpreter. Otherwise it will be - * hidden in a safe interpreter. */ -} TkCmd; - -static TkCmd commands[] = { - /* - * Commands that are part of the intrinsics: - */ - - {"bell", Tk_BellCmd, NULL, 0}, - {"bind", Tk_BindCmd, NULL, 1}, - {"bindtags", Tk_BindtagsCmd, NULL, 1}, - {"clipboard", Tk_ClipboardCmd, NULL, 0}, - {"destroy", Tk_DestroyCmd, NULL, 1}, - {"event", Tk_EventCmd, NULL, 1}, - {"focus", Tk_FocusCmd, NULL, 1}, - {"font", NULL, Tk_FontObjCmd, 1}, - {"grab", Tk_GrabCmd, NULL, 0}, - {"grid", Tk_GridCmd, NULL, 1}, - {"image", Tk_ImageCmd, NULL, 1}, - {"lower", Tk_LowerCmd, NULL, 1}, - {"option", Tk_OptionCmd, NULL, 1}, - {"pack", Tk_PackCmd, NULL, 1}, - {"place", Tk_PlaceCmd, NULL, 1}, - {"raise", Tk_RaiseCmd, NULL, 1}, - {"selection", Tk_SelectionCmd, NULL, 0}, - {"tk", NULL, Tk_TkObjCmd, 0}, - {"tkwait", Tk_TkwaitCmd, NULL, 1}, - {"tk_chooseColor", Tk_ChooseColorCmd, NULL, 0}, - {"tk_getOpenFile", Tk_GetOpenFileCmd, NULL, 0}, - {"tk_getSaveFile", Tk_GetSaveFileCmd, NULL, 0}, - {"tk_messageBox", Tk_MessageBoxCmd, NULL, 0}, - {"update", Tk_UpdateCmd, NULL, 1}, - {"winfo", NULL, Tk_WinfoObjCmd, 1}, - {"wm", Tk_WmCmd, NULL, 0}, - - /* - * Widget class commands. - */ - {"button", Tk_ButtonCmd, NULL, 1}, - {"canvas", Tk_CanvasCmd, NULL, 1}, - {"checkbutton", Tk_CheckbuttonCmd, NULL, 1}, - {"entry", Tk_EntryCmd, NULL, 1}, - {"frame", Tk_FrameCmd, NULL, 1}, - {"label", Tk_LabelCmd, NULL, 1}, - {"listbox", Tk_ListboxCmd, NULL, 1}, - {"menu", Tk_MenuCmd, NULL, 0}, - {"menubutton", Tk_MenubuttonCmd, NULL, 1}, - {"message", Tk_MessageCmd, NULL, 1}, - {"radiobutton", Tk_RadiobuttonCmd, NULL, 1}, - {"scale", Tk_ScaleCmd, NULL, 1}, - {"scrollbar", Tk_ScrollbarCmd, NULL, 1}, - {"text", Tk_TextCmd, NULL, 1}, - {"toplevel", Tk_ToplevelCmd, NULL, 0}, - - /* - * Misc. - */ - -#ifdef MAC_TCL - {"unsupported1", TkUnsupported1Cmd, NULL, 1}, -#endif - {(char *) NULL, (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0} -}; - -/* - * The variables and table below are used to parse arguments from - * the "argv" variable in Tk_Init. - */ - -static int synchronize = 0; -static char *name = NULL; -static char *display = NULL; -static char *geometry = NULL; -static char *colormap = NULL; -static char *use = NULL; -static char *visual = NULL; -static int rest = 0; - -static Tk_ArgvInfo argTable[] = { - {"-colormap", TK_ARGV_STRING, (char *) NULL, (char *) &colormap, - "Colormap for main window"}, - {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display, - "Display to use"}, - {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry, - "Initial geometry for window"}, - {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name, - "Name to use for application"}, - {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize, - "Use synchronous mode for display server"}, - {"-visual", TK_ARGV_STRING, (char *) NULL, (char *) &visual, - "Visual for main window"}, - {"-use", TK_ARGV_STRING, (char *) NULL, (char *) &use, - "Id of window in which to embed application"}, - {"--", TK_ARGV_REST, (char *) 1, (char *) &rest, - "Pass all remaining arguments through to script"}, - {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL, - (char *) NULL} -}; - -/* - * Forward declarations to procedures defined later in this file: - */ - -static Tk_Window CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window parent, char *name, char *screenName)); -static void DeleteWindowsExitProc _ANSI_ARGS_(( - ClientData clientData)); -static TkDisplay * GetScreen _ANSI_ARGS_((Tcl_Interp *interp, - char *screenName, int *screenPtr)); -static int Initialize _ANSI_ARGS_((Tcl_Interp *interp)); -static int NameWindow _ANSI_ARGS_((Tcl_Interp *interp, - TkWindow *winPtr, TkWindow *parentPtr, - char *name)); -static void OpenIM _ANSI_ARGS_((TkDisplay *dispPtr)); -static void UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr)); - -/* - *---------------------------------------------------------------------- - * - * CreateTopLevelWindow -- - * - * Make a new window that will be at top-level (its parent will - * be the root window of a screen). - * - * Results: - * The return value is a token for the new window, or NULL if - * an error prevented the new window from being created. If - * NULL is returned, an error message will be left in - * interp->result. - * - * Side effects: - * A new window structure is allocated locally. An X - * window is NOT initially created, but will be created - * the first time the window is mapped. - * - *---------------------------------------------------------------------- - */ - -static Tk_Window -CreateTopLevelWindow(interp, parent, name, screenName) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Window parent; /* Token for logical parent of new window - * (used for naming, options, etc.). May - * be NULL. */ - char *name; /* Name for new window; if parent is - * non-NULL, must be unique among parent's - * children. */ - char *screenName; /* Name of screen on which to create - * window. NULL means use DISPLAY environment - * variable to determine. Empty string means - * use parent's screen, or DISPLAY if no - * parent. */ -{ - register TkWindow *winPtr; - register TkDisplay *dispPtr; - int screenId; - - if (!initialized) { - initialized = 1; - tkActiveUid = Tk_GetUid("active"); - tkDisabledUid = Tk_GetUid("disabled"); - tkNormalUid = Tk_GetUid("normal"); - - /* - * Create built-in image types. - */ - - Tk_CreateImageType(&tkBitmapImageType); - Tk_CreateImageType(&tkPhotoImageType); - - /* - * Create built-in photo image formats. - */ - - Tk_CreatePhotoImageFormat(&tkImgFmtGIF); - Tk_CreatePhotoImageFormat(&tkImgFmtPPM); - - /* - * Create exit handler to delete all windows when the application - * exits. - */ - - Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL); - } - - if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) { - dispPtr = ((TkWindow *) parent)->dispPtr; - screenId = Tk_ScreenNumber(parent); - } else { - dispPtr = GetScreen(interp, screenName, &screenId); - if (dispPtr == NULL) { - return (Tk_Window) NULL; - } - } - - winPtr = TkAllocWindow(dispPtr, screenId, (TkWindow *) parent); - - /* - * Force the window to use a border pixel instead of border pixmap. - * This is needed for the case where the window doesn't use the - * default visual. In this case, the default border is a pixmap - * inherited from the root window, which won't work because it will - * have the wrong visual. - */ - - winPtr->dirtyAtts |= CWBorderPixel; - - /* - * (Need to set the TK_TOP_LEVEL flag immediately here; otherwise - * Tk_DestroyWindow will core dump if it is called before the flag - * has been set.) - */ - - winPtr->flags |= TK_TOP_LEVEL; - - if (parent != NULL) { - if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) { - Tk_DestroyWindow((Tk_Window) winPtr); - return (Tk_Window) NULL; - } - } - TkWmNewWindow(winPtr); - - return (Tk_Window) winPtr; -} - -/* - *---------------------------------------------------------------------- - * - * GetScreen -- - * - * Given a string name for a display-plus-screen, find the - * TkDisplay structure for the display and return the screen - * number too. - * - * Results: - * The return value is a pointer to information about the display, - * or NULL if the display couldn't be opened. In this case, an - * error message is left in interp->result. The location at - * *screenPtr is overwritten with the screen number parsed from - * screenName. - * - * Side effects: - * A new connection is opened to the display if there is no - * connection already. A new TkDisplay data structure is also - * setup, if necessary. - * - *---------------------------------------------------------------------- - */ - -static TkDisplay * -GetScreen(interp, screenName, screenPtr) - Tcl_Interp *interp; /* Place to leave error message. */ - char *screenName; /* Name for screen. NULL or empty means - * use DISPLAY envariable. */ - int *screenPtr; /* Where to store screen number. */ -{ - register TkDisplay *dispPtr; - char *p; - int screenId; - size_t length; - - /* - * Separate the screen number from the rest of the display - * name. ScreenName is assumed to have the syntax - * <display>.<screen> with the dot and the screen being - * optional. - */ - - screenName = TkGetDefaultScreenName(interp, screenName); - if (screenName == NULL) { - interp->result = - "no display name and no $DISPLAY environment variable"; - return (TkDisplay *) NULL; - } - length = strlen(screenName); - screenId = 0; - p = screenName+length-1; - while (isdigit(UCHAR(*p)) && (p != screenName)) { - p--; - } - if ((*p == '.') && (p[1] != '\0')) { - length = p - screenName; - screenId = strtoul(p+1, (char **) NULL, 10); - } - - /* - * See if we already have a connection to this display. If not, - * then open a new connection. - */ - - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { - if (dispPtr == NULL) { - dispPtr = TkpOpenDisplay(screenName); - if (dispPtr == NULL) { - Tcl_AppendResult(interp, "couldn't connect to display \"", - screenName, "\"", (char *) NULL); - return (TkDisplay *) NULL; - } - dispPtr->nextPtr = tkDisplayList; - dispPtr->name = (char *) ckalloc((unsigned) (length+1)); - dispPtr->lastEventTime = CurrentTime; - strncpy(dispPtr->name, screenName, length); - dispPtr->name[length] = '\0'; - dispPtr->bindInfoStale = 1; - dispPtr->modeModMask = 0; - dispPtr->metaModMask = 0; - dispPtr->altModMask = 0; - dispPtr->numModKeyCodes = 0; - dispPtr->modKeyCodes = NULL; - OpenIM(dispPtr); - dispPtr->errorPtr = NULL; - dispPtr->deleteCount = 0; - dispPtr->commTkwin = NULL; - dispPtr->selectionInfoPtr = NULL; - dispPtr->multipleAtom = None; - dispPtr->clipWindow = NULL; - dispPtr->clipboardActive = 0; - dispPtr->clipboardAppPtr = NULL; - dispPtr->clipTargetPtr = NULL; - dispPtr->atomInit = 0; - dispPtr->cursorFont = None; - dispPtr->grabWinPtr = NULL; - dispPtr->eventualGrabWinPtr = NULL; - dispPtr->buttonWinPtr = NULL; - dispPtr->serverWinPtr = NULL; - dispPtr->firstGrabEventPtr = NULL; - dispPtr->lastGrabEventPtr = NULL; - dispPtr->grabFlags = 0; - TkInitXId(dispPtr); - dispPtr->destroyCount = 0; - dispPtr->lastDestroyRequest = 0; - dispPtr->cmapPtr = NULL; - dispPtr->implicitWinPtr = NULL; - dispPtr->focusPtr = NULL; - dispPtr->stressPtr = NULL; - dispPtr->delayedMotionPtr = NULL; - Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS); - dispPtr->refCount = 0; - - tkDisplayList = dispPtr; - break; - } - if ((strncmp(dispPtr->name, screenName, length) == 0) - && (dispPtr->name[length] == '\0')) { - break; - } - } - if (screenId >= ScreenCount(dispPtr->display)) { - sprintf(interp->result, "bad screen number \"%d\"", screenId); - return (TkDisplay *) NULL; - } - *screenPtr = screenId; - return dispPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkGetDisplay -- - * - * Given an X display, TkGetDisplay returns the TkDisplay - * structure for the display. - * - * Results: - * The return value is a pointer to information about the display, - * or NULL if the display did not have a TkDisplay structure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -TkDisplay * -TkGetDisplay(display) - Display *display; /* X's display pointer */ -{ - TkDisplay *dispPtr; - - for (dispPtr = tkDisplayList; dispPtr != NULL; - dispPtr = dispPtr->nextPtr) { - if (dispPtr->display == display) { - break; - } - } - return dispPtr; -} - -/* - *-------------------------------------------------------------- - * - * TkAllocWindow -- - * - * This procedure creates and initializes a TkWindow structure. - * - * Results: - * The return value is a pointer to the new window. - * - * Side effects: - * A new window structure is allocated and all its fields are - * initialized. - * - *-------------------------------------------------------------- - */ - -TkWindow * -TkAllocWindow(dispPtr, screenNum, parentPtr) - TkDisplay *dispPtr; /* Display associated with new window. */ - int screenNum; /* Index of screen for new window. */ - TkWindow *parentPtr; /* Parent from which this window should - * inherit visual information. NULL means - * use screen defaults instead of - * inheriting. */ -{ - register TkWindow *winPtr; - - winPtr = (TkWindow *) ckalloc(sizeof(TkWindow)); - winPtr->display = dispPtr->display; - winPtr->dispPtr = dispPtr; - winPtr->screenNum = screenNum; - if ((parentPtr != NULL) && (parentPtr->display == winPtr->display) - && (parentPtr->screenNum == winPtr->screenNum)) { - winPtr->visual = parentPtr->visual; - winPtr->depth = parentPtr->depth; - } else { - winPtr->visual = DefaultVisual(dispPtr->display, screenNum); - winPtr->depth = DefaultDepth(dispPtr->display, screenNum); - } - winPtr->window = None; - winPtr->childList = NULL; - winPtr->lastChildPtr = NULL; - winPtr->parentPtr = NULL; - winPtr->nextPtr = NULL; - winPtr->mainPtr = NULL; - winPtr->pathName = NULL; - winPtr->nameUid = NULL; - winPtr->classUid = NULL; - winPtr->changes = defChanges; - winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth; - winPtr->atts = defAtts; - if ((parentPtr != NULL) && (parentPtr->display == winPtr->display) - && (parentPtr->screenNum == winPtr->screenNum)) { - winPtr->atts.colormap = parentPtr->atts.colormap; - } else { - winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum); - } - winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity; - winPtr->flags = 0; - winPtr->handlerList = NULL; -#ifdef TK_USE_INPUT_METHODS - winPtr->inputContext = NULL; -#endif /* TK_USE_INPUT_METHODS */ - winPtr->tagPtr = NULL; - winPtr->numTags = 0; - winPtr->optionLevel = -1; - winPtr->selHandlerList = NULL; - winPtr->geomMgrPtr = NULL; - winPtr->geomData = NULL; - winPtr->reqWidth = winPtr->reqHeight = 1; - winPtr->internalBorderWidth = 0; - winPtr->wmInfoPtr = NULL; - winPtr->classProcsPtr = NULL; - winPtr->instanceData = NULL; - winPtr->privatePtr = NULL; - - return winPtr; -} - -/* - *---------------------------------------------------------------------- - * - * NameWindow -- - * - * This procedure is invoked to give a window a name and insert - * the window into the hierarchy associated with a particular - * application. - * - * Results: - * A standard Tcl return value. - * - * Side effects: - * See above. - * - *---------------------------------------------------------------------- - */ - -static int -NameWindow(interp, winPtr, parentPtr, name) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - register TkWindow *winPtr; /* Window that is to be named and inserted. */ - TkWindow *parentPtr; /* Pointer to logical parent for winPtr - * (used for naming, options, etc.). */ - char *name; /* Name for winPtr; must be unique among - * parentPtr's children. */ -{ -#define FIXED_SIZE 200 - char staticSpace[FIXED_SIZE]; - char *pathName; - int new; - Tcl_HashEntry *hPtr; - int length1, length2; - - /* - * Setup all the stuff except name right away, then do the name stuff - * last. This is so that if the name stuff fails, everything else - * will be properly initialized (needed to destroy the window cleanly - * after the naming failure). - */ - winPtr->parentPtr = parentPtr; - winPtr->nextPtr = NULL; - if (parentPtr->childList == NULL) { - parentPtr->childList = winPtr; - } else { - parentPtr->lastChildPtr->nextPtr = winPtr; - } - parentPtr->lastChildPtr = winPtr; - winPtr->mainPtr = parentPtr->mainPtr; - winPtr->mainPtr->refCount++; - winPtr->nameUid = Tk_GetUid(name); - - /* - * Don't permit names that start with an upper-case letter: this - * will just cause confusion with class names in the option database. - */ - - if (isupper(UCHAR(name[0]))) { - Tcl_AppendResult(interp, - "window name starts with an upper-case letter: \"", - name, "\"", (char *) NULL); - return TCL_ERROR; - } - - /* - * To permit names of arbitrary length, must be prepared to malloc - * a buffer to hold the new path name. To run fast in the common - * case where names are short, use a fixed-size buffer on the - * stack. - */ - - length1 = strlen(parentPtr->pathName); - length2 = strlen(name); - if ((length1+length2+2) <= FIXED_SIZE) { - pathName = staticSpace; - } else { - pathName = (char *) ckalloc((unsigned) (length1+length2+2)); - } - if (length1 == 1) { - pathName[0] = '.'; - strcpy(pathName+1, name); - } else { - strcpy(pathName, parentPtr->pathName); - pathName[length1] = '.'; - strcpy(pathName+length1+1, name); - } - hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new); - if (pathName != staticSpace) { - ckfree(pathName); - } - if (!new) { - Tcl_AppendResult(interp, "window name \"", name, - "\" already exists in parent", (char *) NULL); - return TCL_ERROR; - } - Tcl_SetHashValue(hPtr, winPtr); - winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkCreateMainWindow -- - * - * Make a new main window. A main window is a special kind of - * top-level window used as the outermost window in an - * application. - * - * Results: - * The return value is a token for the new window, or NULL if - * an error prevented the new window from being created. If - * NULL is returned, an error message will be left in - * interp->result. - * - * Side effects: - * A new window structure is allocated locally; "interp" is - * associated with the window and registered for "send" commands - * under "baseName". BaseName may be extended with an instance - * number in the form "#2" if necessary to make it globally - * unique. Tk-related commands are bound into interp. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -TkCreateMainWindow(interp, screenName, baseName) - Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - char *screenName; /* Name of screen on which to create - * window. Empty or NULL string means - * use DISPLAY environment variable. */ - char *baseName; /* Base name for application; usually of the - * form "prog instance". */ -{ - Tk_Window tkwin; - int dummy; - int isSafe; - Tcl_HashEntry *hPtr; - register TkMainInfo *mainPtr; - register TkWindow *winPtr; - register TkCmd *cmdPtr; - - /* - * Panic if someone updated the TkWindow structure without - * also updating the Tk_FakeWin structure (or vice versa). - */ - - if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) { - panic("TkWindow and Tk_FakeWin are not the same size"); - } - - /* - * Create the basic TkWindow structure. - */ - - tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName, - screenName); - if (tkwin == NULL) { - return NULL; - } - - /* - * Create the TkMainInfo structure for this application, and set - * up name-related information for the new window. - */ - - winPtr = (TkWindow *) tkwin; - mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo)); - mainPtr->winPtr = winPtr; - mainPtr->refCount = 1; - mainPtr->interp = interp; - Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS); - TkBindInit(mainPtr); - TkFontPkgInit(mainPtr); - mainPtr->tlFocusPtr = NULL; - mainPtr->displayFocusPtr = NULL; - mainPtr->optionRootPtr = NULL; - Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS); - mainPtr->strictMotif = 0; - if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif, - TCL_LINK_BOOLEAN) != TCL_OK) { - Tcl_ResetResult(interp); - } - mainPtr->nextPtr = tkMainWindowList; - tkMainWindowList = mainPtr; - winPtr->mainPtr = mainPtr; - hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy); - Tcl_SetHashValue(hPtr, winPtr); - winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr); - - /* - * We have just created another Tk application; increment the refcount - * on the display pointer. - */ - - winPtr->dispPtr->refCount++; - - /* - * Register the interpreter for "send" purposes. - */ - - winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName)); - - /* - * Bind in Tk's commands. - */ - - isSafe = Tcl_IsSafe(interp); - for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { - if ((cmdPtr->cmdProc == NULL) && (cmdPtr->objProc == NULL)) { - panic("TkCreateMainWindow: builtin command with NULL string and object procs"); - } - if (cmdPtr->cmdProc != NULL) { - Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc, - (ClientData) tkwin, (void (*) _ANSI_ARGS_((ClientData))) NULL); - } else { - Tcl_CreateObjCommand(interp, cmdPtr->name, cmdPtr->objProc, - (ClientData) tkwin, NULL); - } - if (isSafe) { - if (!(cmdPtr->isSafe)) { - Tcl_HideCommand(interp, cmdPtr->name, cmdPtr->name); - } - } - } - - /* - * Set variables for the intepreter. - */ - - Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY); - - numMainWindows++; - return tkwin; -} - -/* - *-------------------------------------------------------------- - * - * Tk_CreateWindow -- - * - * Create a new internal or top-level window as a child of an - * existing window. - * - * Results: - * The return value is a token for the new window. This - * is not the same as X's token for the window. If an error - * occurred in creating the window (e.g. no such display or - * screen), then an error message is left in interp->result and - * NULL is returned. - * - * Side effects: - * A new window structure is allocated locally. An X - * window is not initially created, but will be created - * the first time the window is mapped. - * - *-------------------------------------------------------------- - */ - -Tk_Window -Tk_CreateWindow(interp, parent, name, screenName) - Tcl_Interp *interp; /* Interpreter to use for error reporting. - * Interp->result is assumed to be - * initialized by the caller. */ - Tk_Window parent; /* Token for parent of new window. */ - char *name; /* Name for new window. Must be unique - * among parent's children. */ - char *screenName; /* If NULL, new window will be internal on - * same screen as its parent. If non-NULL, - * gives name of screen on which to create - * new window; window will be a top-level - * window. */ -{ - TkWindow *parentPtr = (TkWindow *) parent; - TkWindow *winPtr; - - if ((parentPtr != NULL) && (parentPtr->flags & TK_ALREADY_DEAD)) { - Tcl_AppendResult(interp, - "can't create window: parent has been destroyed", - (char *) NULL); - return NULL; - } else if ((parentPtr != NULL) && - (parentPtr->flags & TK_CONTAINER)) { - Tcl_AppendResult(interp, - "can't create window: its parent has -container = yes", - (char *) NULL); - return NULL; - } - if (screenName == NULL) { - winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum, - parentPtr); - if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) { - Tk_DestroyWindow((Tk_Window) winPtr); - return NULL; - } else { - return (Tk_Window) winPtr; - } - } else { - return CreateTopLevelWindow(interp, parent, name, screenName); - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CreateWindowFromPath -- - * - * This procedure is similar to Tk_CreateWindow except that - * it uses a path name to create the window, rather than a - * parent and a child name. - * - * Results: - * The return value is a token for the new window. This - * is not the same as X's token for the window. If an error - * occurred in creating the window (e.g. no such display or - * screen), then an error message is left in interp->result and - * NULL is returned. - * - * Side effects: - * A new window structure is allocated locally. An X - * window is not initially created, but will be created - * the first time the window is mapped. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName) - Tcl_Interp *interp; /* Interpreter to use for error reporting. - * Interp->result is assumed to be - * initialized by the caller. */ - Tk_Window tkwin; /* Token for any window in application - * that is to contain new window. */ - char *pathName; /* Path name for new window within the - * application of tkwin. The parent of - * this window must already exist, but - * the window itself must not exist. */ - char *screenName; /* If NULL, new window will be on same - * screen as its parent. If non-NULL, - * gives name of screen on which to create - * new window; window will be a top-level - * window. */ -{ -#define FIXED_SPACE 5 - char fixedSpace[FIXED_SPACE+1]; - char *p; - Tk_Window parent; - int numChars; - - /* - * Strip the parent's name out of pathName (it's everything up - * to the last dot). There are two tricky parts: (a) must - * copy the parent's name somewhere else to avoid modifying - * the pathName string (for large names, space for the copy - * will have to be malloc'ed); (b) must special-case the - * situation where the parent is ".". - */ - - p = strrchr(pathName, '.'); - if (p == NULL) { - Tcl_AppendResult(interp, "bad window path name \"", pathName, - "\"", (char *) NULL); - return NULL; - } - numChars = p-pathName; - if (numChars > FIXED_SPACE) { - p = (char *) ckalloc((unsigned) (numChars+1)); - } else { - p = fixedSpace; - } - if (numChars == 0) { - *p = '.'; - p[1] = '\0'; - } else { - strncpy(p, pathName, (size_t) numChars); - p[numChars] = '\0'; - } - - /* - * Find the parent window. - */ - - parent = Tk_NameToWindow(interp, p, tkwin); - if (p != fixedSpace) { - ckfree(p); - } - if (parent == NULL) { - return NULL; - } - if (((TkWindow *) parent)->flags & TK_ALREADY_DEAD) { - Tcl_AppendResult(interp, - "can't create window: parent has been destroyed", (char *) NULL); - return NULL; - } else if (((TkWindow *) parent)->flags & TK_CONTAINER) { - Tcl_AppendResult(interp, - "can't create window: its parent has -container = yes", - (char *) NULL); - return NULL; - } - - /* - * Create the window. - */ - - if (screenName == NULL) { - TkWindow *parentPtr = (TkWindow *) parent; - TkWindow *winPtr; - - winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum, - parentPtr); - if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1) - != TCL_OK) { - Tk_DestroyWindow((Tk_Window) winPtr); - return NULL; - } else { - return (Tk_Window) winPtr; - } - } else { - return CreateTopLevelWindow(interp, parent, pathName+numChars+1, - screenName); - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_DestroyWindow -- - * - * Destroy an existing window. After this call, the caller - * should never again use the token. - * - * Results: - * None. - * - * Side effects: - * The window is deleted, along with all of its children. - * Relevant callback procedures are invoked. - * - *-------------------------------------------------------------- - */ - -void -Tk_DestroyWindow(tkwin) - Tk_Window tkwin; /* Window to destroy. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - TkDisplay *dispPtr = winPtr->dispPtr; - XEvent event; - - if (winPtr->flags & TK_ALREADY_DEAD) { - /* - * A destroy event binding caused the window to be destroyed - * again. Ignore the request. - */ - - return; - } - winPtr->flags |= TK_ALREADY_DEAD; - - /* - * Some cleanup needs to be done immediately, rather than later, - * because it needs information that will be destoyed before we - * get to the main cleanup point. For example, TkFocusDeadWindow - * needs to access the parentPtr field from a window, but if - * a Destroy event handler deletes the window's parent this - * field will be NULL before the main cleanup point is reached. - */ - - TkFocusDeadWindow(winPtr); - - /* - * If this is a main window, remove it from the list of main - * windows. This needs to be done now (rather than later with - * all the other main window cleanup) to handle situations where - * a destroy binding for a window calls "exit". In this case - * the child window cleanup isn't complete when exit is called, - * so the reference count of its application doesn't go to zero - * when exit calls Tk_DestroyWindow on ".", so the main window - * doesn't get removed from the list and exit loops infinitely. - * Even worse, if "destroy ." is called by the destroy binding - * before calling "exit", "exit" will attempt to destroy - * mainPtr->winPtr, which no longer exists, and there may be a - * core dump. - * - * Also decrement the display refcount so that if this is the - * last Tk application in this process on this display, the display - * can be closed and its data structures deleted. - */ - - if (winPtr->mainPtr->winPtr == winPtr) { - dispPtr->refCount--; - if (tkMainWindowList == winPtr->mainPtr) { - tkMainWindowList = winPtr->mainPtr->nextPtr; - } else { - TkMainInfo *prevPtr; - - for (prevPtr = tkMainWindowList; - prevPtr->nextPtr != winPtr->mainPtr; - prevPtr = prevPtr->nextPtr) { - /* Empty loop body. */ - } - prevPtr->nextPtr = winPtr->mainPtr->nextPtr; - } - numMainWindows--; - } - - /* - * Recursively destroy children. - */ - - dispPtr->destroyCount++; - while (winPtr->childList != NULL) { - TkWindow *childPtr; - childPtr = winPtr->childList; - childPtr->flags |= TK_DONT_DESTROY_WINDOW; - Tk_DestroyWindow((Tk_Window) childPtr); - if (winPtr->childList == childPtr) { - /* - * The child didn't remove itself from the child list, so - * let's remove it here. This can happen in some strange - * conditions, such as when a Delete event handler for a - * window deletes the window's parent. - */ - - winPtr->childList = childPtr->nextPtr; - childPtr->parentPtr = NULL; - } - } - if ((winPtr->flags & (TK_CONTAINER|TK_BOTH_HALVES)) - == (TK_CONTAINER|TK_BOTH_HALVES)) { - /* - * This is the container for an embedded application, and - * the embedded application is also in this process. Delete - * the embedded window in-line here, for the same reasons we - * delete children in-line (otherwise, for example, the Tk - * window may appear to exist even though its X window is - * gone; this could cause errors). Special note: it's possible - * that the embedded window has already been deleted, in which - * case TkpGetOtherWindow will return NULL. - */ - - TkWindow *childPtr; - childPtr = TkpGetOtherWindow(winPtr); - if (childPtr != NULL) { - childPtr->flags |= TK_DONT_DESTROY_WINDOW; - Tk_DestroyWindow((Tk_Window) childPtr); - } - } - - /* - * Generate a DestroyNotify event. In order for the DestroyNotify - * event to be processed correctly, need to make sure the window - * exists. This is a bit of a kludge, and may be unnecessarily - * expensive, but without it no event handlers will get called for - * windows that don't exist yet. - * - * Note: if the window's pathName is NULL it means that the window - * was not successfully initialized in the first place, so we should - * not make the window exist or generate the event. - */ - - if (winPtr->pathName != NULL) { - if (winPtr->window == None) { - Tk_MakeWindowExist(tkwin); - } - event.type = DestroyNotify; - event.xdestroywindow.serial = - LastKnownRequestProcessed(winPtr->display); - event.xdestroywindow.send_event = False; - event.xdestroywindow.display = winPtr->display; - event.xdestroywindow.event = winPtr->window; - event.xdestroywindow.window = winPtr->window; - Tk_HandleEvent(&event); - } - - /* - * Cleanup the data structures associated with this window. - */ - - if (winPtr->flags & TK_TOP_LEVEL) { - TkWmDeadWindow(winPtr); - } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) { - TkWmRemoveFromColormapWindows(winPtr); - } - if (winPtr->window != None) { -#if defined(MAC_TCL) || defined(__WIN32__) - XDestroyWindow(winPtr->display, winPtr->window); -#else - if ((winPtr->flags & TK_TOP_LEVEL) - || !(winPtr->flags & TK_DONT_DESTROY_WINDOW)) { - /* - * The parent has already been destroyed and this isn't - * a top-level window, so this window will be destroyed - * implicitly when the parent's X window is destroyed; - * it's much faster not to do an explicit destroy of this - * X window. - */ - - dispPtr->lastDestroyRequest = NextRequest(winPtr->display); - XDestroyWindow(winPtr->display, winPtr->window); - } -#endif - TkFreeWindowId(dispPtr, winPtr->window); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable, - (char *) winPtr->window)); - winPtr->window = None; - } - dispPtr->destroyCount--; - UnlinkWindow(winPtr); - TkEventDeadWindow(winPtr); - TkBindDeadWindow(winPtr); -#ifdef TK_USE_INPUT_METHODS - if (winPtr->inputContext != NULL) { - XDestroyIC(winPtr->inputContext); - } -#endif /* TK_USE_INPUT_METHODS */ - if (winPtr->tagPtr != NULL) { - TkFreeBindingTags(winPtr); - } - TkOptionDeadWindow(winPtr); - TkSelDeadWindow(winPtr); - TkGrabDeadWindow(winPtr); - if (winPtr->mainPtr != NULL) { - if (winPtr->pathName != NULL) { - Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable, - (ClientData) winPtr->pathName); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, - winPtr->pathName)); - } - winPtr->mainPtr->refCount--; - if (winPtr->mainPtr->refCount == 0) { - register TkCmd *cmdPtr; - - /* - * We just deleted the last window in the application. Delete - * the TkMainInfo structure too and replace all of Tk's commands - * with dummy commands that return errors. Also delete the - * "send" command to unregister the interpreter. - * - * NOTE: Only replace the commands it if the interpreter is - * not being deleted. If it *is*, the interpreter cleanup will - * do all the needed work. - */ - - if ((winPtr->mainPtr->interp != NULL) && - (!Tcl_InterpDeleted(winPtr->mainPtr->interp))) { - for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { - Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name, - TkDeadAppCmd, (ClientData) NULL, - (void (*) _ANSI_ARGS_((ClientData))) NULL); - } - Tcl_CreateCommand(winPtr->mainPtr->interp, "send", - TkDeadAppCmd, (ClientData) NULL, - (void (*) _ANSI_ARGS_((ClientData))) NULL); - Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif"); - } - - Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable); - TkBindFree(winPtr->mainPtr); - TkFontPkgFree(winPtr->mainPtr); - TkDeleteAllImages(winPtr->mainPtr); - - /* - * When embedding Tk into other applications, make sure - * that all destroy events reach the server. Otherwise - * the embedding application may also attempt to destroy - * the windows, resulting in an X error - */ - - if (winPtr->flags & TK_EMBEDDED) { - XSync(winPtr->display,False) ; - } - ckfree((char *) winPtr->mainPtr); - - /* - * If no other applications are using the display, close the - * display now and relinquish its data structures. - */ - - if (dispPtr->refCount <= 0) { -#ifdef NOT_YET - /* - * I have disabled this code because on Windows there are - * still order dependencies in close-down. All displays - * and resources will get closed down properly anyway at - * exit, through the exit handler. - */ - - TkDisplay *theDispPtr, *backDispPtr; - - /* - * Splice this display out of the list of displays. - */ - - for (theDispPtr = tkDisplayList, backDispPtr = NULL; - (theDispPtr != winPtr->dispPtr) && - (theDispPtr != NULL); - theDispPtr = theDispPtr->nextPtr) { - backDispPtr = theDispPtr; - } - if (theDispPtr == NULL) { - panic("could not find display to close!"); - } - if (backDispPtr == NULL) { - tkDisplayList = theDispPtr->nextPtr; - } else { - backDispPtr->nextPtr = theDispPtr->nextPtr; - } - - /* - * Found and spliced it out, now actually do the cleanup. - */ - - if (dispPtr->name != NULL) { - ckfree(dispPtr->name); - } - - Tcl_DeleteHashTable(&(dispPtr->winTable)); - - /* - * Cannot yet close the display because we still have - * order of deletion problems. Defer until exit handling - * instead. At that time, the display will cleanly shut - * down (hopefully..). (JYL) - */ - - TkpCloseDisplay(dispPtr); - - /* - * There is lots more to clean up, we leave it at this for - * the time being. - */ -#endif - } - } - } - ckfree((char *) winPtr); -} - -/* - *-------------------------------------------------------------- - * - * Tk_MapWindow -- - * - * Map a window within its parent. This may require the - * window and/or its parents to actually be created. - * - * Results: - * None. - * - * Side effects: - * The given window will be mapped. Windows may also - * be created. - * - *-------------------------------------------------------------- - */ - -void -Tk_MapWindow(tkwin) - Tk_Window tkwin; /* Token for window to map. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - XEvent event; - - if (winPtr->flags & TK_MAPPED) { - return; - } - if (winPtr->window == None) { - Tk_MakeWindowExist(tkwin); - } - if (winPtr->flags & TK_TOP_LEVEL) { - /* - * Lots of special processing has to be done for top-level - * windows. Let tkWm.c handle everything itself. - */ - - TkWmMapWindow(winPtr); - return; - } - winPtr->flags |= TK_MAPPED; - XMapWindow(winPtr->display, winPtr->window); - event.type = MapNotify; - event.xmap.serial = LastKnownRequestProcessed(winPtr->display); - event.xmap.send_event = False; - event.xmap.display = winPtr->display; - event.xmap.event = winPtr->window; - event.xmap.window = winPtr->window; - event.xmap.override_redirect = winPtr->atts.override_redirect; - Tk_HandleEvent(&event); -} - -/* - *-------------------------------------------------------------- - * - * Tk_MakeWindowExist -- - * - * Ensure that a particular window actually exists. This - * procedure shouldn't normally need to be invoked from - * outside the Tk package, but may be needed if someone - * wants to manipulate a window before mapping it. - * - * Results: - * None. - * - * Side effects: - * When the procedure returns, the X window associated with - * tkwin is guaranteed to exist. This may require the - * window's ancestors to be created also. - * - *-------------------------------------------------------------- - */ - -void -Tk_MakeWindowExist(tkwin) - Tk_Window tkwin; /* Token for window. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - TkWindow *winPtr2; - Window parent; - Tcl_HashEntry *hPtr; - int new; - - if (winPtr->window != None) { - return; - } - - if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) { - parent = XRootWindow(winPtr->display, winPtr->screenNum); - } else { - if (winPtr->parentPtr->window == None) { - Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr); - } - parent = winPtr->parentPtr->window; - } - - if (winPtr->classProcsPtr != NULL - && winPtr->classProcsPtr->createProc != NULL) { - winPtr->window = (*winPtr->classProcsPtr->createProc)(tkwin, parent, - winPtr->instanceData); - } else { - winPtr->window = TkpMakeWindow(winPtr, parent); - } - - hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable, - (char *) winPtr->window, &new); - Tcl_SetHashValue(hPtr, winPtr); - winPtr->dirtyAtts = 0; - winPtr->dirtyChanges = 0; -#ifdef TK_USE_INPUT_METHODS - winPtr->inputContext = NULL; -#endif /* TK_USE_INPUT_METHODS */ - - if (!(winPtr->flags & TK_TOP_LEVEL)) { - /* - * If any siblings higher up in the stacking order have already - * been created then move this window to its rightful position - * in the stacking order. - * - * NOTE: this code ignores any changes anyone might have made - * to the sibling and stack_mode field of the window's attributes, - * so it really isn't safe for these to be manipulated except - * by calling Tk_RestackWindow. - */ - - for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL; - winPtr2 = winPtr2->nextPtr) { - if ((winPtr2->window != None) - && !(winPtr2->flags & (TK_TOP_LEVEL|TK_REPARENTED))) { - XWindowChanges changes; - changes.sibling = winPtr2->window; - changes.stack_mode = Below; - XConfigureWindow(winPtr->display, winPtr->window, - CWSibling|CWStackMode, &changes); - break; - } - } - - /* - * If this window has a different colormap than its parent, add - * the window to the WM_COLORMAP_WINDOWS property for its top-level. - */ - - if ((winPtr->parentPtr != NULL) && - (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) { - TkWmAddToColormapWindows(winPtr); - winPtr->flags |= TK_WM_COLORMAP_WINDOW; - } - } - - /* - * Issue a ConfigureNotify event if there were deferred configuration - * changes (but skip it if the window is being deleted; the - * ConfigureNotify event could cause problems if we're being called - * from Tk_DestroyWindow under some conditions). - */ - - if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY) - && !(winPtr->flags & TK_ALREADY_DEAD)){ - winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY; - TkDoConfigureNotify(winPtr); - } -} - -/* - *-------------------------------------------------------------- - * - * Tk_UnmapWindow, etc. -- - * - * There are several procedures under here, each of which - * mirrors an existing X procedure. In addition to performing - * the functions of the corresponding procedure, each - * procedure also updates the local window structure and - * synthesizes an X event (if the window's structure is being - * managed internally). - * - * Results: - * See the manual entries. - * - * Side effects: - * See the manual entries. - * - *-------------------------------------------------------------- - */ - -void -Tk_UnmapWindow(tkwin) - Tk_Window tkwin; /* Token for window to unmap. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) { - return; - } - if (winPtr->flags & TK_TOP_LEVEL) { - /* - * Special processing has to be done for top-level windows. Let - * tkWm.c handle everything itself. - */ - - TkWmUnmapWindow(winPtr); - return; - } - winPtr->flags &= ~TK_MAPPED; - XUnmapWindow(winPtr->display, winPtr->window); - if (!(winPtr->flags & TK_TOP_LEVEL)) { - XEvent event; - - event.type = UnmapNotify; - event.xunmap.serial = LastKnownRequestProcessed(winPtr->display); - event.xunmap.send_event = False; - event.xunmap.display = winPtr->display; - event.xunmap.event = winPtr->window; - event.xunmap.window = winPtr->window; - event.xunmap.from_configure = False; - Tk_HandleEvent(&event); - } -} - -void -Tk_ConfigureWindow(tkwin, valueMask, valuePtr) - Tk_Window tkwin; /* Window to re-configure. */ - unsigned int valueMask; /* Mask indicating which parts of - * *valuePtr are to be used. */ - XWindowChanges *valuePtr; /* New values. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if (valueMask & CWX) { - winPtr->changes.x = valuePtr->x; - } - if (valueMask & CWY) { - winPtr->changes.y = valuePtr->y; - } - if (valueMask & CWWidth) { - winPtr->changes.width = valuePtr->width; - } - if (valueMask & CWHeight) { - winPtr->changes.height = valuePtr->height; - } - if (valueMask & CWBorderWidth) { - winPtr->changes.border_width = valuePtr->border_width; - } - if (valueMask & (CWSibling|CWStackMode)) { - panic("Can't set sibling or stack mode from Tk_ConfigureWindow."); - } - - if (winPtr->window != None) { - XConfigureWindow(winPtr->display, winPtr->window, - valueMask, valuePtr); - TkDoConfigureNotify(winPtr); - } else { - winPtr->dirtyChanges |= valueMask; - winPtr->flags |= TK_NEED_CONFIG_NOTIFY; - } -} - -void -Tk_MoveWindow(tkwin, x, y) - Tk_Window tkwin; /* Window to move. */ - int x, y; /* New location for window (within - * parent). */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->changes.x = x; - winPtr->changes.y = y; - if (winPtr->window != None) { - XMoveWindow(winPtr->display, winPtr->window, x, y); - TkDoConfigureNotify(winPtr); - } else { - winPtr->dirtyChanges |= CWX|CWY; - winPtr->flags |= TK_NEED_CONFIG_NOTIFY; - } -} - -void -Tk_ResizeWindow(tkwin, width, height) - Tk_Window tkwin; /* Window to resize. */ - int width, height; /* New dimensions for window. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->changes.width = (unsigned) width; - winPtr->changes.height = (unsigned) height; - if (winPtr->window != None) { - XResizeWindow(winPtr->display, winPtr->window, (unsigned) width, - (unsigned) height); - TkDoConfigureNotify(winPtr); - } else { - winPtr->dirtyChanges |= CWWidth|CWHeight; - winPtr->flags |= TK_NEED_CONFIG_NOTIFY; - } -} - -void -Tk_MoveResizeWindow(tkwin, x, y, width, height) - Tk_Window tkwin; /* Window to move and resize. */ - int x, y; /* New location for window (within - * parent). */ - int width, height; /* New dimensions for window. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->changes.x = x; - winPtr->changes.y = y; - winPtr->changes.width = (unsigned) width; - winPtr->changes.height = (unsigned) height; - if (winPtr->window != None) { - XMoveResizeWindow(winPtr->display, winPtr->window, x, y, - (unsigned) width, (unsigned) height); - TkDoConfigureNotify(winPtr); - } else { - winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight; - winPtr->flags |= TK_NEED_CONFIG_NOTIFY; - } -} - -void -Tk_SetWindowBorderWidth(tkwin, width) - Tk_Window tkwin; /* Window to modify. */ - int width; /* New border width for window. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->changes.border_width = width; - if (winPtr->window != None) { - XSetWindowBorderWidth(winPtr->display, winPtr->window, - (unsigned) width); - TkDoConfigureNotify(winPtr); - } else { - winPtr->dirtyChanges |= CWBorderWidth; - winPtr->flags |= TK_NEED_CONFIG_NOTIFY; - } -} - -void -Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr) - Tk_Window tkwin; /* Window to manipulate. */ - unsigned long valueMask; /* OR'ed combination of bits, - * indicating which fields of - * *attsPtr are to be used. */ - register XSetWindowAttributes *attsPtr; - /* New values for some attributes. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if (valueMask & CWBackPixmap) { - winPtr->atts.background_pixmap = attsPtr->background_pixmap; - } - if (valueMask & CWBackPixel) { - winPtr->atts.background_pixel = attsPtr->background_pixel; - } - if (valueMask & CWBorderPixmap) { - winPtr->atts.border_pixmap = attsPtr->border_pixmap; - } - if (valueMask & CWBorderPixel) { - winPtr->atts.border_pixel = attsPtr->border_pixel; - } - if (valueMask & CWBitGravity) { - winPtr->atts.bit_gravity = attsPtr->bit_gravity; - } - if (valueMask & CWWinGravity) { - winPtr->atts.win_gravity = attsPtr->win_gravity; - } - if (valueMask & CWBackingStore) { - winPtr->atts.backing_store = attsPtr->backing_store; - } - if (valueMask & CWBackingPlanes) { - winPtr->atts.backing_planes = attsPtr->backing_planes; - } - if (valueMask & CWBackingPixel) { - winPtr->atts.backing_pixel = attsPtr->backing_pixel; - } - if (valueMask & CWOverrideRedirect) { - winPtr->atts.override_redirect = attsPtr->override_redirect; - } - if (valueMask & CWSaveUnder) { - winPtr->atts.save_under = attsPtr->save_under; - } - if (valueMask & CWEventMask) { - winPtr->atts.event_mask = attsPtr->event_mask; - } - if (valueMask & CWDontPropagate) { - winPtr->atts.do_not_propagate_mask - = attsPtr->do_not_propagate_mask; - } - if (valueMask & CWColormap) { - winPtr->atts.colormap = attsPtr->colormap; - } - if (valueMask & CWCursor) { - winPtr->atts.cursor = attsPtr->cursor; - } - - if (winPtr->window != None) { - XChangeWindowAttributes(winPtr->display, winPtr->window, - valueMask, attsPtr); - } else { - winPtr->dirtyAtts |= valueMask; - } -} - -void -Tk_SetWindowBackground(tkwin, pixel) - Tk_Window tkwin; /* Window to manipulate. */ - unsigned long pixel; /* Pixel value to use for - * window's background. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->atts.background_pixel = pixel; - - if (winPtr->window != None) { - XSetWindowBackground(winPtr->display, winPtr->window, pixel); - } else { - winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap) - | CWBackPixel; - } -} - -void -Tk_SetWindowBackgroundPixmap(tkwin, pixmap) - Tk_Window tkwin; /* Window to manipulate. */ - Pixmap pixmap; /* Pixmap to use for window's - * background. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->atts.background_pixmap = pixmap; - - if (winPtr->window != None) { - XSetWindowBackgroundPixmap(winPtr->display, - winPtr->window, pixmap); - } else { - winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel) - | CWBackPixmap; - } -} - -void -Tk_SetWindowBorder(tkwin, pixel) - Tk_Window tkwin; /* Window to manipulate. */ - unsigned long pixel; /* Pixel value to use for - * window's border. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->atts.border_pixel = pixel; - - if (winPtr->window != None) { - XSetWindowBorder(winPtr->display, winPtr->window, pixel); - } else { - winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap) - | CWBorderPixel; - } -} - -void -Tk_SetWindowBorderPixmap(tkwin, pixmap) - Tk_Window tkwin; /* Window to manipulate. */ - Pixmap pixmap; /* Pixmap to use for window's - * border. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->atts.border_pixmap = pixmap; - - if (winPtr->window != None) { - XSetWindowBorderPixmap(winPtr->display, - winPtr->window, pixmap); - } else { - winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel) - | CWBorderPixmap; - } -} - -void -Tk_DefineCursor(tkwin, cursor) - Tk_Window tkwin; /* Window to manipulate. */ - Tk_Cursor cursor; /* Cursor to use for window (may be None). */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - -#ifdef MAC_TCL - winPtr->atts.cursor = (XCursor) cursor; -#else - winPtr->atts.cursor = (Cursor) cursor; -#endif - - if (winPtr->window != None) { - XDefineCursor(winPtr->display, winPtr->window, winPtr->atts.cursor); - } else { - winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor; - } -} - -void -Tk_UndefineCursor(tkwin) - Tk_Window tkwin; /* Window to manipulate. */ -{ - Tk_DefineCursor(tkwin, None); -} - -void -Tk_SetWindowColormap(tkwin, colormap) - Tk_Window tkwin; /* Window to manipulate. */ - Colormap colormap; /* Colormap to use for window. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->atts.colormap = colormap; - - if (winPtr->window != None) { - XSetWindowColormap(winPtr->display, winPtr->window, colormap); - if (!(winPtr->flags & TK_TOP_LEVEL)) { - TkWmAddToColormapWindows(winPtr); - winPtr->flags |= TK_WM_COLORMAP_WINDOW; - } - } else { - winPtr->dirtyAtts |= CWColormap; - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SetWindowVisual -- - * - * This procedure is called to specify a visual to be used - * for a Tk window when it is created. This procedure, if - * called at all, must be called before the X window is created - * (i.e. before Tk_MakeWindowExist is called). - * - * Results: - * The return value is 1 if successful, or 0 if the X window has - * been already created. - * - * Side effects: - * The information given is stored for when the window is created. - * - *---------------------------------------------------------------------- - */ - -int -Tk_SetWindowVisual(tkwin, visual, depth, colormap) - Tk_Window tkwin; /* Window to manipulate. */ - Visual *visual; /* New visual for window. */ - int depth; /* New depth for window. */ - Colormap colormap; /* An appropriate colormap for the visual. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - if( winPtr->window != None ){ - /* Too late! */ - return 0; - } - - winPtr->visual = visual; - winPtr->depth = depth; - winPtr->atts.colormap = colormap; - winPtr->dirtyAtts |= CWColormap; - - /* - * The following code is needed to make sure that the window doesn't - * inherit the parent's border pixmap, which would result in a BadMatch - * error. - */ - - if (!(winPtr->dirtyAtts & CWBorderPixmap)) { - winPtr->dirtyAtts |= CWBorderPixel; - } - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * TkDoConfigureNotify -- - * - * Generate a ConfigureNotify event describing the current - * configuration of a window. - * - * Results: - * None. - * - * Side effects: - * An event is generated and processed by Tk_HandleEvent. - * - *---------------------------------------------------------------------- - */ - -void -TkDoConfigureNotify(winPtr) - register TkWindow *winPtr; /* Window whose configuration - * was just changed. */ -{ - XEvent event; - - event.type = ConfigureNotify; - event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display); - event.xconfigure.send_event = False; - event.xconfigure.display = winPtr->display; - event.xconfigure.event = winPtr->window; - event.xconfigure.window = winPtr->window; - event.xconfigure.x = winPtr->changes.x; - event.xconfigure.y = winPtr->changes.y; - event.xconfigure.width = winPtr->changes.width; - event.xconfigure.height = winPtr->changes.height; - event.xconfigure.border_width = winPtr->changes.border_width; - if (winPtr->changes.stack_mode == Above) { - event.xconfigure.above = winPtr->changes.sibling; - } else { - event.xconfigure.above = None; - } - event.xconfigure.override_redirect = winPtr->atts.override_redirect; - Tk_HandleEvent(&event); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SetClass -- - * - * This procedure is used to give a window a class. - * - * Results: - * None. - * - * Side effects: - * A new class is stored for tkwin, replacing any existing - * class for it. - * - *---------------------------------------------------------------------- - */ - -void -Tk_SetClass(tkwin, className) - Tk_Window tkwin; /* Token for window to assign class. */ - char *className; /* New class for tkwin. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->classUid = Tk_GetUid(className); - if (winPtr->flags & TK_TOP_LEVEL) { - TkWmSetClass(winPtr); - } - TkOptionClassChanged(winPtr); -} - -/* - *---------------------------------------------------------------------- - * - * TkSetClassProcs -- - * - * This procedure is used to set the class procedures and - * instance data for a window. - * - * Results: - * None. - * - * Side effects: - * A new set of class procedures and instance data is stored - * for tkwin, replacing any existing values. - * - *---------------------------------------------------------------------- - */ - -void -TkSetClassProcs(tkwin, procs, instanceData) - Tk_Window tkwin; /* Token for window to modify. */ - TkClassProcs *procs; /* Class procs structure. */ - ClientData instanceData; /* Data to be passed to class procedures. */ -{ - register TkWindow *winPtr = (TkWindow *) tkwin; - - winPtr->classProcsPtr = procs; - winPtr->instanceData = instanceData; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_NameToWindow -- - * - * Given a string name for a window, this procedure - * returns the token for the window, if there exists a - * window corresponding to the given name. - * - * Results: - * The return result is either a token for the window corresponding - * to "name", or else NULL to indicate that there is no such - * window. In this case, an error message is left in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -Tk_NameToWindow(interp, pathName, tkwin) - Tcl_Interp *interp; /* Where to report errors. */ - char *pathName; /* Path name of window. */ - Tk_Window tkwin; /* Token for window: name is assumed to - * belong to the same main window as tkwin. */ -{ - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable, - pathName); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "bad window path name \"", - pathName, "\"", (char *) NULL); - return NULL; - } - return (Tk_Window) Tcl_GetHashValue(hPtr); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_IdToWindow -- - * - * Given an X display and window ID, this procedure returns the - * Tk token for the window, if there exists a Tk window corresponding - * to the given ID. - * - * Results: - * The return result is either a token for the window corresponding - * to the given X id, or else NULL to indicate that there is no such - * window. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -Tk_IdToWindow(display, window) - Display *display; /* X display containing the window. */ - Window window; /* X window window id. */ -{ - TkDisplay *dispPtr; - Tcl_HashEntry *hPtr; - - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { - if (dispPtr == NULL) { - return NULL; - } - if (dispPtr->display == display) { - break; - } - } - - hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window); - if (hPtr == NULL) { - return NULL; - } - return (Tk_Window) Tcl_GetHashValue(hPtr); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DisplayName -- - * - * Return the textual name of a window's display. - * - * Results: - * The return value is the string name of the display associated - * with tkwin. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -Tk_DisplayName(tkwin) - Tk_Window tkwin; /* Window whose display name is desired. */ -{ - return ((TkWindow *) tkwin)->dispPtr->name; -} - -/* - *---------------------------------------------------------------------- - * - * UnlinkWindow -- - * - * This procedure removes a window from the childList of its - * parent. - * - * Results: - * None. - * - * Side effects: - * The window is unlinked from its childList. - * - *---------------------------------------------------------------------- - */ - -static void -UnlinkWindow(winPtr) - TkWindow *winPtr; /* Child window to be unlinked. */ -{ - TkWindow *prevPtr; - - if (winPtr->parentPtr == NULL) { - return; - } - prevPtr = winPtr->parentPtr->childList; - if (prevPtr == winPtr) { - winPtr->parentPtr->childList = winPtr->nextPtr; - if (winPtr->nextPtr == NULL) { - winPtr->parentPtr->lastChildPtr = NULL; - } - } else { - while (prevPtr->nextPtr != winPtr) { - prevPtr = prevPtr->nextPtr; - if (prevPtr == NULL) { - panic("UnlinkWindow couldn't find child in parent"); - } - } - prevPtr->nextPtr = winPtr->nextPtr; - if (winPtr->nextPtr == NULL) { - winPtr->parentPtr->lastChildPtr = prevPtr; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * Tk_RestackWindow -- - * - * Change a window's position in the stacking order. - * - * Results: - * TCL_OK is normally returned. If other is not a descendant - * of tkwin's parent then TCL_ERROR is returned and tkwin is - * not repositioned. - * - * Side effects: - * Tkwin is repositioned in the stacking order. - * - *---------------------------------------------------------------------- - */ - -int -Tk_RestackWindow(tkwin, aboveBelow, other) - Tk_Window tkwin; /* Token for window whose position in - * the stacking order is to change. */ - int aboveBelow; /* Indicates new position of tkwin relative - * to other; must be Above or Below. */ - Tk_Window other; /* Tkwin will be moved to a position that - * puts it just above or below this window. - * If NULL then tkwin goes above or below - * all windows in the same parent. */ -{ - TkWindow *winPtr = (TkWindow *) tkwin; - TkWindow *otherPtr = (TkWindow *) other; - XWindowChanges changes; - unsigned int mask; - - - /* - * Special case: if winPtr is a top-level window then just find - * the top-level ancestor of otherPtr and restack winPtr above - * otherPtr without changing any of Tk's childLists. - */ - - changes.stack_mode = aboveBelow; - mask = CWStackMode; - if (winPtr->flags & TK_TOP_LEVEL) { - while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) { - otherPtr = otherPtr->parentPtr; - } - TkWmRestackToplevel(winPtr, aboveBelow, otherPtr); - return TCL_OK; - } - - /* - * Find an ancestor of otherPtr that is a sibling of winPtr. - */ - - if (winPtr->parentPtr == NULL) { - /* - * Window is going to be deleted shortly; don't do anything. - */ - - return TCL_OK; - } - if (otherPtr == NULL) { - if (aboveBelow == Above) { - otherPtr = winPtr->parentPtr->lastChildPtr; - } else { - otherPtr = winPtr->parentPtr->childList; - } - } else { - while (winPtr->parentPtr != otherPtr->parentPtr) { - if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) { - return TCL_ERROR; - } - otherPtr = otherPtr->parentPtr; - } - } - if (otherPtr == winPtr) { - return TCL_OK; - } - - /* - * Reposition winPtr in the stacking order. - */ - - UnlinkWindow(winPtr); - if (aboveBelow == Above) { - winPtr->nextPtr = otherPtr->nextPtr; - if (winPtr->nextPtr == NULL) { - winPtr->parentPtr->lastChildPtr = winPtr; - } - otherPtr->nextPtr = winPtr; - } else { - TkWindow *prevPtr; - - prevPtr = winPtr->parentPtr->childList; - if (prevPtr == otherPtr) { - winPtr->parentPtr->childList = winPtr; - } else { - while (prevPtr->nextPtr != otherPtr) { - prevPtr = prevPtr->nextPtr; - } - prevPtr->nextPtr = winPtr; - } - winPtr->nextPtr = otherPtr; - } - - /* - * Notify the X server of the change. If winPtr hasn't yet been - * created then there's no need to tell the X server now, since - * the stacking order will be handled properly when the window - * is finally created. - */ - - if (winPtr->window != None) { - changes.stack_mode = Above; - for (otherPtr = winPtr->nextPtr; otherPtr != NULL; - otherPtr = otherPtr->nextPtr) { - if ((otherPtr->window != None) - && !(otherPtr->flags & (TK_TOP_LEVEL|TK_REPARENTED))){ - changes.sibling = otherPtr->window; - changes.stack_mode = Below; - mask = CWStackMode|CWSibling; - break; - } - } - XConfigureWindow(winPtr->display, winPtr->window, mask, &changes); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_MainWindow -- - * - * Returns the main window for an application. - * - * Results: - * If interp has a Tk application associated with it, the main - * window for the application is returned. Otherwise NULL is - * returned and an error message is left in interp->result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -Tk_MainWindow(interp) - Tcl_Interp *interp; /* Interpreter that embodies the - * application. Used for error - * reporting also. */ -{ - TkMainInfo *mainPtr; - - for (mainPtr = tkMainWindowList; mainPtr != NULL; - mainPtr = mainPtr->nextPtr) { - if (mainPtr->interp == interp) { - return (Tk_Window) mainPtr->winPtr; - } - } - interp->result = "this isn't a Tk application"; - return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_StrictMotif -- - * - * Indicates whether strict Motif compliance has been specified - * for the given window. - * - * Results: - * The return value is 1 if strict Motif compliance has been - * requested for tkwin's application by setting the tk_strictMotif - * variable in its interpreter to a true value. 0 is returned - * if tk_strictMotif has a false value. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_StrictMotif(tkwin) - Tk_Window tkwin; /* Window whose application is - * to be checked. */ -{ - return ((TkWindow *) tkwin)->mainPtr->strictMotif; -} - -/* - *-------------------------------------------------------------- - * - * OpenIM -- - * - * Tries to open an X input method, associated with the - * given display. Right now we can only deal with a bare-bones - * input style: no preedit, and no status. - * - * Results: - * Stores the input method in dispPtr->inputMethod; if there isn't - * a suitable input method, then NULL is stored in dispPtr->inputMethod. - * - * Side effects: - * An input method gets opened. - * - *-------------------------------------------------------------- - */ - -static void -OpenIM(dispPtr) - TkDisplay *dispPtr; /* Tk's structure for the display. */ -{ -#ifndef TK_USE_INPUT_METHODS - return; -#else - unsigned short i; - XIMStyles *stylePtr; - - dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL); - if (dispPtr->inputMethod == NULL) { - return; - } - - if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr, - NULL) != NULL) || (stylePtr == NULL)) { - goto error; - } - for (i = 0; i < stylePtr->count_styles; i++) { - if (stylePtr->supported_styles[i] - == (XIMPreeditNothing|XIMStatusNothing)) { - XFree(stylePtr); - return; - } - } - XFree(stylePtr); - - error: - - /* - * Should close the input method, but this causes core dumps on some - * systems (e.g. Solaris 2.3 as of 1/6/95). - * XCloseIM(dispPtr->inputMethod); - */ - dispPtr->inputMethod = NULL; - return; -#endif /* TK_USE_INPUT_METHODS */ -} - -/* - *---------------------------------------------------------------------- - * - * Tk_GetNumMainWindows -- - * - * This procedure returns the number of main windows currently - * open in this process. - * - * Results: - * The number of main windows open in this process. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -Tk_GetNumMainWindows() -{ - return numMainWindows; -} - -/* - *---------------------------------------------------------------------- - * - * DeleteWindowsExitProc -- - * - * This procedure is invoked as an exit handler. It deletes all - * of the main windows in the process. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -DeleteWindowsExitProc(clientData) - ClientData clientData; /* Not used. */ -{ - TkDisplay *displayPtr, *nextPtr; - Tcl_Interp *interp; - - while (tkMainWindowList != NULL) { - /* - * We must protect the interpreter while deleting the window, - * because of <Destroy> bindings which could destroy the interpreter - * while the window is being deleted. This would leave frames on - * the call stack pointing at deleted memory, causing core dumps. - */ - - interp = tkMainWindowList->winPtr->mainPtr->interp; - Tcl_Preserve((ClientData) interp); - Tk_DestroyWindow((Tk_Window) tkMainWindowList->winPtr); - Tcl_Release((ClientData) interp); - } - - displayPtr = tkDisplayList; - tkDisplayList = NULL; - - /* - * Iterate destroying the displays until no more displays remain. - * It is possible for displays to get recreated during exit by any - * code that calls GetScreen, so we must destroy these new displays - * as well as the old ones. - */ - - for (displayPtr = tkDisplayList; - displayPtr != NULL; - displayPtr = tkDisplayList) { - - /* - * Now iterate over the current list of open displays, and first - * set the global pointer to NULL so we will be able to notice if - * any new displays got created during deletion of the current set. - * We must also do this to ensure that Tk_IdToWindow does not find - * the old display as it is being destroyed, when it wants to see - * if it needs to dispatch a message. - */ - - for (tkDisplayList = NULL; displayPtr != NULL; displayPtr = nextPtr) { - nextPtr = displayPtr->nextPtr; - if (displayPtr->name != (char *) NULL) { - ckfree(displayPtr->name); - } - Tcl_DeleteHashTable(&(displayPtr->winTable)); - TkpCloseDisplay(displayPtr); - } - } - - numMainWindows = 0; - tkMainWindowList = NULL; - initialized = 0; - tkDisabledUid = NULL; - tkActiveUid = NULL; - tkNormalUid = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_Init -- - * - * This procedure is invoked to add Tk to an interpreter. It - * incorporates all of Tk's commands into the interpreter and - * creates the main window for a new Tk application. If the - * interpreter contains a variable "argv", this procedure - * extracts several arguments from that variable, uses them - * to configure the main window, and modifies argv to exclude - * the arguments (see the "wish" documentation for a list of - * the arguments that are extracted). - * - * Results: - * Returns a standard Tcl completion code and sets interp->result - * if there is an error. - * - * Side effects: - * Depends on various initialization scripts that get invoked. - * - *---------------------------------------------------------------------- - */ - -int -Tk_Init(interp) - Tcl_Interp *interp; /* Interpreter to initialize. */ -{ - return Initialize(interp); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_SafeInit -- - * - * This procedure is invoked to add Tk to a safe interpreter. It - * invokes the internal procedure that does the real work. - * - * Results: - * Returns a standard Tcl completion code and sets interp->result - * if there is an error. - * - * Side effects: - * Depends on various initialization scripts that are invoked. - * - *---------------------------------------------------------------------- - */ - -int -Tk_SafeInit(interp) - Tcl_Interp *interp; /* Interpreter to initialize. */ -{ - /* - * Initialize the interpreter with Tk, safely. This removes - * all the Tk commands that are unsafe. - * - * Rationale: - * - * - Toplevel and menu are unsafe because they can be used to cover - * the entire screen and to steal input from the user. - * - Continuous ringing of the bell is a nuisance. - * - Cannot allow access to the clipboard because a malicious script - * can replace the contents with the string "rm -r *" and lead to - * surprises when the contents of the clipboard are pasted. We do - * not currently hide the selection command.. Should we? - * - Cannot allow send because it can be used to cause unsafe - * interpreters to execute commands. The tk command recreates the - * send command, so that too must be hidden. - * - Focus can be used to grab the focus away from another window, - * in effect stealing user input. Cannot allow that. - * NOTE: We currently do *not* hide focus as it would make it - * impossible to provide keyboard input to Tk in a safe interpreter. - * - Grab can be used to block the user from using any other apps - * on the screen. - * - Tkwait can block the containing process forever. Use bindings, - * fileevents and split the protocol into before-the-wait and - * after-the-wait parts. More work but necessary. - * - Wm is unsafe because (if toplevels are allowed, in the future) - * it can be used to remove decorations, move windows around, cover - * the entire screen etc etc. - * - * Current risks: - * - * - No CPU time limit, no memory allocation limits, no color limits. - * - * The actual code called is the same as Tk_Init but Tcl_IsSafe() - * is checked at several places to differentiate the two initialisations. - */ - - return Initialize(interp); -} - -/* - *---------------------------------------------------------------------- - * - * Initialize -- - * - * - * Results: - * A standard Tcl result. Also leaves an error message in interp->result - * if there was an error. - * - * Side effects: - * Depends on the initialization scripts that are invoked. - * - *---------------------------------------------------------------------- - */ - -static int -Initialize(interp) - Tcl_Interp *interp; /* Interpreter to initialize. */ -{ - char *p; - int argc, code; - char **argv, *args[20]; - Tcl_DString class; - char buffer[30]; - - /* - * Start by initializing all the static variables to default acceptable - * values so that no information is leaked from a previous run of this - * code. - */ - - synchronize = 0; - name = NULL; - display = NULL; - geometry = NULL; - colormap = NULL; - use = NULL; - visual = NULL; - rest = 0; - - /* - * We start by resetting the result because it might not be clean - */ - Tcl_ResetResult(interp); - - if (Tcl_IsSafe(interp)) { - /* - * Get the clearance to start Tk and the "argv" parameters - * from the master. - */ - Tcl_DString ds; - - /* - * Step 1 : find the master and construct the interp name - * (could be a function if new APIs were ok). - * We could also construct the path while walking, but there - * is no API to get the name of an interp either. - */ - Tcl_Interp *master = interp; - - while (1) { - master = Tcl_GetMaster(master); - if (master == NULL) { - Tcl_DStringFree(&ds); - Tcl_AppendResult(interp, "NULL master", (char *) NULL); - return TCL_ERROR; - } - if (!Tcl_IsSafe(master)) { - /* Found the trusted master. */ - break; - } - } - /* - * Construct the name (rewalk...) - */ - if (Tcl_GetInterpPath(master, interp) != TCL_OK) { - Tcl_AppendResult(interp, "error in Tcl_GetInterpPath", - (char *) NULL); - return TCL_ERROR; - } - /* - * Build the string to eval. - */ - Tcl_DStringInit(&ds); - Tcl_DStringAppendElement(&ds, "::safe::TkInit"); - Tcl_DStringAppendElement(&ds, Tcl_GetStringResult(master)); - - /* - * Step 2 : Eval in the master. The argument is the *reversed* - * interp path of the slave. - */ - - if (Tcl_Eval(master, Tcl_DStringValue(&ds)) != TCL_OK) { - /* - * We might want to transfer the error message or not. - * We don't. (no API to do it and maybe security reasons). - */ - Tcl_DStringFree(&ds); - Tcl_AppendResult(interp, - "not allowed to start Tk by master's safe::TkInit", - (char *) NULL); - return TCL_ERROR; - } - Tcl_DStringFree(&ds); - /* - * Use the master's result as argv. - * Note: We don't use the Obj interfaces to avoid dealing with - * cross interp refcounting and changing the code below. - */ - - p = Tcl_GetStringResult(master); - } else { - /* - * If there is an "argv" variable, get its value, extract out - * relevant arguments from it, and rewrite the variable without - * the arguments that we used. - */ - - p = Tcl_GetVar2(interp, "argv", (char *) NULL, TCL_GLOBAL_ONLY); - } - argv = NULL; - if (p != NULL) { - if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) { - argError: - Tcl_AddErrorInfo(interp, - "\n (processing arguments in argv variable)"); - return TCL_ERROR; - } - if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, - argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS) - != TCL_OK) { - ckfree((char *) argv); - goto argError; - } - p = Tcl_Merge(argc, argv); - Tcl_SetVar2(interp, "argv", (char *) NULL, p, TCL_GLOBAL_ONLY); - sprintf(buffer, "%d", argc); - Tcl_SetVar2(interp, "argc", (char *) NULL, buffer, TCL_GLOBAL_ONLY); - ckfree(p); - } - - /* - * Figure out the application's name and class. - */ - - Tcl_DStringInit(&class); - if (name == NULL) { - int offset; - TkpGetAppName(interp, &class); - offset = Tcl_DStringLength(&class)+1; - Tcl_DStringSetLength(&class, offset); - Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1); - name = Tcl_DStringValue(&class) + offset; - } else { - Tcl_DStringAppend(&class, name, -1); - } - - p = Tcl_DStringValue(&class); - if (islower(UCHAR(*p))) { - *p = toupper(UCHAR(*p)); - } - - /* - * Create an argument list for creating the top-level window, - * using the information parsed from argv, if any. - */ - - args[0] = "toplevel"; - args[1] = "."; - args[2] = "-class"; - args[3] = Tcl_DStringValue(&class); - argc = 4; - if (display != NULL) { - args[argc] = "-screen"; - args[argc+1] = display; - argc += 2; - - /* - * If this is the first application for this process, save - * the display name in the DISPLAY environment variable so - * that it will be available to subprocesses created by us. - */ - - if (numMainWindows == 0) { - Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY); - } - } - if (colormap != NULL) { - args[argc] = "-colormap"; - args[argc+1] = colormap; - argc += 2; - colormap = NULL; - } - if (use != NULL) { - args[argc] = "-use"; - args[argc+1] = use; - argc += 2; - use = NULL; - } - if (visual != NULL) { - args[argc] = "-visual"; - args[argc+1] = visual; - argc += 2; - visual = NULL; - } - args[argc] = NULL; - code = TkCreateFrame((ClientData) NULL, interp, argc, args, 1, name); - - Tcl_DStringFree(&class); - if (code != TCL_OK) { - goto done; - } - Tcl_ResetResult(interp); - if (synchronize) { - XSynchronize(Tk_Display(Tk_MainWindow(interp)), True); - } - - /* - * Set the geometry of the main window, if requested. Put the - * requested geometry into the "geometry" variable. - */ - - if (geometry != NULL) { - Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY); - code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL); - if (code != TCL_OK) { - goto done; - } - geometry = NULL; - } - if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) { - code = TCL_ERROR; - goto done; - } - code = Tcl_PkgProvide(interp, "Tk", TK_VERSION); - if (code != TCL_OK) { - goto done; - } - - /* - * Invoke platform-specific initialization. - */ - - code = TkpInit(interp); - - done: - if (argv != NULL) { - ckfree((char *) argv); - } - return code; -} |