Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | merge trunk |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | tip-262 |
Files: | files | file ages | folders |
SHA3-256: |
2eac67b28e1d6262f0b6cec639a3fe77 |
User & Date: | dkf 2019-05-16 21:27:17.932 |
Context
2019-05-16
| ||
22:22 | Fix some tests. Add some test cases. check-in: 42f90406 user: dkf tags: tip-262 | |
21:27 | merge trunk check-in: 2eac67b2 user: dkf tags: tip-262 | |
19:55 | Fix bug [d1989fb7cf]: In Aqua the root window appears before Tk_Mainloop is called. check-in: a2e1c6c6 user: culler tags: trunk | |
2019-04-13
| ||
17:59 | Added tests check-in: e685524c user: dkf tags: tip-262 | |
Changes
Changes to doc/CrtItemType.3.
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 | Tk_ItemTranslateProc *\fItranslateProc\fR; Tk_ItemIndexProc *\fIindexProc\fR; Tk_ItemCursorProc *\fIicursorProc\fR; Tk_ItemSelectionProc *\fIselectionProc\fR; Tk_ItemInsertProc *\fIinsertProc\fR; Tk_ItemDCharsProc *\fIdCharsProc\fR; Tk_ItemType *\fInextPtr\fR; } \fBTk_ItemType\fR; .CE .PP The fields of a Tk_ItemType structure are described in more detail later in this manual entry. When \fBTk_CreateItemType\fR is called, its \fItypePtr\fR argument must point to a structure with all of the fields initialized | > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | Tk_ItemTranslateProc *\fItranslateProc\fR; Tk_ItemIndexProc *\fIindexProc\fR; Tk_ItemCursorProc *\fIicursorProc\fR; Tk_ItemSelectionProc *\fIselectionProc\fR; Tk_ItemInsertProc *\fIinsertProc\fR; Tk_ItemDCharsProc *\fIdCharsProc\fR; Tk_ItemType *\fInextPtr\fR; .VS "8.7, TIP164" Tk_ItemRotateProc *\fIrotateProc\fR; .VE "8.7, TIP164" } \fBTk_ItemType\fR; .CE .PP The fields of a Tk_ItemType structure are described in more detail later in this manual entry. When \fBTk_CreateItemType\fR is called, its \fItypePtr\fR argument must point to a structure with all of the fields initialized |
︙ | ︙ | |||
545 546 547 548 549 550 551 552 553 554 555 556 557 558 | .CE .PP The \fIcanvas\fR and \fIitemPtr\fR arguments have the usual meaning, and \fIdeltaX\fR and \fIdeltaY\fR give the amounts that should be added to each x and y coordinate within the item. The type manager should adjust the item's coordinates and update the bounding box in the item's header. .SS INDEXPROC .PP \fItypePtr\->indexProc\fR is invoked by Tk to translate a string index specification into a numerical index, for example during the \fBindex\fR widget command. It is only relevant for item types that support indexable text or coordinates; \fItypePtr\->indexProc\fR may be specified as NULL for non-textual | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | .CE .PP The \fIcanvas\fR and \fIitemPtr\fR arguments have the usual meaning, and \fIdeltaX\fR and \fIdeltaY\fR give the amounts that should be added to each x and y coordinate within the item. The type manager should adjust the item's coordinates and update the bounding box in the item's header. .SS ROTATEPROC .VS "8.7, TIP164" .PP \fItypePtr\->rotateProc\fR is invoked by Tk to rotate a canvas item during the \fBrotate\fR widget command. The procedure must match the following prototype: .PP .CS typedef void \fBTk_ItemRotateProc\fR( Tk_Canvas \fIcanvas\fR, Tk_Item *\fIitemPtr\fR, double \fIoriginX\fR, double \fIoriginY\fR, double \fIangleRad\fR); .CE .PP The \fIcanvas\fR and \fIitemPtr\fR arguments have the usual meaning. \fIoriginX\fR and \fIoriginY\fR specify an origin relative to which the item is to be rotated, and \fIangleRad\fR gives the anticlockwise rotation to be applied in radians. The item should adjust the coordinates of its control points so that where they used to have coordinates \fIx\fR and \fIy\fR, they will have new coordinates \fIx\(fm\fR and \fIy\(fm\fR, where .PP .CS \fIrelX\fR = \fIx\fR - \fIoriginX\fR \fIrelY\fR = \fIy\fR - \fIoriginY\fR \fIx\(fm\fR = \fIoriginX\fR + \fIrelX\fR \(mu cos(\fIangleRad\fR) + \fIrelY\fR \(mu sin(\fIangleRad\fR) \fIy\(fm\fR = \fIoriginY\fR \(mi \fIrelX\fR \(mu sin(\fIangleRad\fR) + \fIrelY\fR \(mu cos(\fIangleRad\fR) .CE .PP The control points for an item are not necessarily the coordinates provided to the item when it is created (or via the \fItypePtr\->coordProc\fR), but could instead be derived from them. \fIrotateProc\fR must also update the bounding box in the item's header. .PP Item types do not need to provide a \fItypePtr\->rotateProc\fR. If the \fItypePtr\->rotateProc\fR is NULL, the \fItypePtr\->coordProc\fR will be used instead to retrieve and update the list of coordinates. .VE "8.7, TIP164" .SS INDEXPROC .PP \fItypePtr\->indexProc\fR is invoked by Tk to translate a string index specification into a numerical index, for example during the \fBindex\fR widget command. It is only relevant for item types that support indexable text or coordinates; \fItypePtr\->indexProc\fR may be specified as NULL for non-textual |
︙ | ︙ |
Changes to doc/GetScroll.3.
︙ | ︙ | |||
11 12 13 14 15 16 17 | .SH NAME Tk_GetScrollInfoObj, Tk_GetScrollInfo \- parse arguments for scrolling commands .SH SYNOPSIS .nf \fB#include <tk.h>\fR .sp int | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | .SH NAME Tk_GetScrollInfoObj, Tk_GetScrollInfo \- parse arguments for scrolling commands .SH SYNOPSIS .nf \fB#include <tk.h>\fR .sp int \fBTk_GetScrollInfoObj(\fIinterp, objc, objv, fractionPtr, stepsPtr\fB)\fR .sp int \fBTk_GetScrollInfo(\fIinterp, argc, argv, fractionPtr, stepsPtr\fB)\fR .SH ARGUMENTS .AS "Tcl_Interp" *fractionPtr .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP int objc in Number of Tcl_Obj's in \fIobjv\fR array. .AP "Tcl_Obj *const" objv[] in |
︙ | ︙ |
Changes to doc/canvas.n.
︙ | ︙ | |||
216 217 218 219 220 221 222 | It is possible to adjust the origin of the canvas coordinate system relative to the origin of the window using the \fBxview\fR and \fByview\fR widget commands; this is typically used for scrolling. Canvases do not support scaling or rotation of the canvas coordinate system relative to the window coordinate system. .PP | | > > > > | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | It is possible to adjust the origin of the canvas coordinate system relative to the origin of the window using the \fBxview\fR and \fByview\fR widget commands; this is typically used for scrolling. Canvases do not support scaling or rotation of the canvas coordinate system relative to the window coordinate system. .PP Individual items may be moved, scaled .VS "8.7, TIP164" or rotated .VE "8.7, TIP164" using widget commands described below. .PP Note that the default origin of the canvas's visible area is coincident with the origin for the whole window as that makes bindings using the mouse position easier to work with; you only need to use the \fBcanvasx\fR and \fBcanvasy\fR widget commands if you adjust the origin of the visible area. However, this also means that any focus ring (as controlled by the \fB\-highlightthickness\fR option) and |
︙ | ︙ | |||
670 671 672 673 674 675 676 | factor can also be given and the photo image will be enlarged. The image background will be filled with the canvas background colour. The canvas widget does not need to be mapped for this widget command to work, but at least one of it's ancestors must be mapped. This command returns an empty string. .TP \fIpathName \fBimove \fItagOrId index x y\fR | < > < | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | factor can also be given and the photo image will be enlarged. The image background will be filled with the canvas background colour. The canvas widget does not need to be mapped for this widget command to work, but at least one of it's ancestors must be mapped. This command returns an empty string. .TP \fIpathName \fBimove \fItagOrId index x y\fR . This command causes the \fIindex\fR'th coordinate of each of the items indicated by \fItagOrId\fR to be relocated to the location (\fIx\fR,\fIy\fR). Each item interprets \fIindex\fR independently according to the rules described in \fBINDICES\fR above. Out of the standard set of items, only line and polygon items may have their coordinates relocated this way. .TP \fIpathName \fBindex \fItagOrId index\fR . This command returns a decimal string giving the numerical index within \fItagOrId\fR corresponding to \fIindex\fR. \fIIndex\fR gives a textual description of the desired position as described in \fBINDICES\fR above. |
︙ | ︙ | |||
762 763 764 765 766 767 768 | Move each of the items given by \fItagOrId\fR in the canvas coordinate space by adding \fIxAmount\fR to the x-coordinate of each point associated with the item and \fIyAmount\fR to the y-coordinate of each point associated with the item. This command returns an empty string. .TP \fIpathName \fBmoveto \fItagOrId xPos yPos\fR | < > < | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | Move each of the items given by \fItagOrId\fR in the canvas coordinate space by adding \fIxAmount\fR to the x-coordinate of each point associated with the item and \fIyAmount\fR to the y-coordinate of each point associated with the item. This command returns an empty string. .TP \fIpathName \fBmoveto \fItagOrId xPos yPos\fR . Move the items given by \fItagOrId\fR in the canvas coordinate space so that the first coordinate pair of the bottommost item with tag \fItagOrId\fR is located at position (\fIxPos\fR,\fIyPos\fR). \fIxPos\fR and \fIyPos\fR may be the empty string, in which case the corresponding coordinate will be unchanged. All items matching \fItagOrId\fR remain in the same positions relative to each other. This command returns an empty string. .TP \fIpathName \fBpostscript \fR?\fIoption value option value ...\fR? . Generate a Postscript representation for part or all of the canvas. If the \fB\-file\fR option is specified then the Postscript is written to a file and an empty string is returned; otherwise the Postscript is returned as the result of the command. |
︙ | ︙ | |||
957 958 959 960 961 962 963 | Note: this command has no effect on window items. Window items always obscure other item types, and the stacking order of window items is determined by the \fBraise\fR command and \fBlower\fR command, not the \fBraise\fR widget command and \fBlower\fR widget command for canvases. .RE .TP \fIpathName \fBrchars \fItagOrId first last string\fR | < > > > > > > > > > > > > > > > > > > > > > | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 | Note: this command has no effect on window items. Window items always obscure other item types, and the stacking order of window items is determined by the \fBraise\fR command and \fBlower\fR command, not the \fBraise\fR widget command and \fBlower\fR widget command for canvases. .RE .TP \fIpathName \fBrchars \fItagOrId first last string\fR . This command causes the text or coordinates between \fIfirst\fR and \fIlast\fR for each of the items indicated by \fItagOrId\fR to be replaced by \fIstring\fR. Each item interprets \fIfirst\fR and \fIlast\fR independently according to the rules described in \fBINDICES\fR above. Out of the standard set of items, text items support this operation by altering their text as directed, and line and polygon items support this operation by altering their coordinate list (in which case \fIstring\fR should be a list of coordinates to use as a replacement). The other items ignore this operation. .TP \fIpathName \fBrotate \fItagOrId xOrigin yOrigin angle\fR .VS "8.7, TIP164" Rotate the coordinates of all of the items given by \fItagOrId\fR in canvas coordinate space. \fIXOrigin\fR and \fIyOrigin\fR identify the origin for the rotation operation and \fIangle\fR identifies the amount to rotate the coordinates anticlockwise, in degrees. (Negative values rotate clockwise.) This command returns an empty string. .RS .PP Implementation note: not all item types work the same with rotations. In particular,\fB bitmap\fR,\fB image\fR,\fB text\fR and\fB window\fR items only rotate their anchor points and do not rotate the items themselves about those points, and the \fBarc\fR, \fBoval\fR and \fBrectangle\fR types rotate about a computed center point instead of moving the bounding box coordinates directly. .PP Some items (currently \fBarc\R and\fB text\fR) have angles in their options; this command \fIdoes not\fR affect those options. .RE .VE "8.7, TIP164" .TP \fIpathName \fBscale \fItagOrId xOrigin yOrigin xScale yScale\fR . Rescale the coordinates of all of the items given by \fItagOrId\fR in canvas coordinate space. \fIXOrigin\fR and \fIyOrigin\fR identify the origin for the scaling operation and \fIxScale\fR and \fIyScale\fR identify the scale |
︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 | \fB\-stipple\fR \fB\-activestipple\fR \fB\-disabledstipple\fR \fB\-state\fR \fB\-tags\fR .DE The following extra options are supported for text items: .TP \fB\-angle \fIrotationDegrees\fR | < > < | 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 | \fB\-stipple\fR \fB\-activestipple\fR \fB\-disabledstipple\fR \fB\-state\fR \fB\-tags\fR .DE The following extra options are supported for text items: .TP \fB\-angle \fIrotationDegrees\fR . \fIRotationDegrees\fR tells how many degrees to rotate the text anticlockwise about the positioning point for the text; it may have any floating-point value from 0.0 to 360.0. For example, if \fIrotationDegrees\fR is \fB90\fR, then the text will be drawn vertically from bottom to top. This option defaults to \fB0.0\fR. .TP \fB\-font \fIfontName\fR Specifies the font to use for the text item. \fIFontName\fR may be any string acceptable to \fBTk_GetFont\fR. If this option is not specified, it defaults to a system-dependent font. .TP |
︙ | ︙ |
Changes to doc/colors.n.
︙ | ︙ | |||
780 781 782 783 784 785 786 | yellow4 139 139 0 YellowGreen 154 205 50 .DE .SH "PORTABILITY ISSUES" .TP \fBMac OS X\fR . | | > | < > | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | yellow4 139 139 0 YellowGreen 154 205 50 .DE .SH "PORTABILITY ISSUES" .TP \fBMac OS X\fR . On macOS, the following additional system colors are available. This first group contains all colors available in the HIToolbox library. (Note that in some cases the actual color values may depend on the current Appearance.) .RS .DS systemActiveAreaFill systemAlertActiveText systemAlertBackgroundActive systemAlertBackgroundInactive systemAlertInactiveText |
︙ | ︙ | |||
896 897 898 899 900 901 902 903 904 905 906 907 908 909 | systemRootMenuActiveText systemRootMenuDisabledText systemRootMenuSelectedText systemScrollBarDelimiterActive systemScrollBarDelimiterInactive systemSecondaryGroupBoxBackground systemSecondaryHighlightColor systemSheetBackground systemSheetBackgroundOpaque systemSheetBackgroundTransparent systemStaticAreaFill systemSystemDetailText systemTabFrontActiveText systemTabFrontInactiveText | > | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 | systemRootMenuActiveText systemRootMenuDisabledText systemRootMenuSelectedText systemScrollBarDelimiterActive systemScrollBarDelimiterInactive systemSecondaryGroupBoxBackground systemSecondaryHighlightColor systemSelectedTabTextColor systemSheetBackground systemSheetBackgroundOpaque systemSheetBackgroundTransparent systemStaticAreaFill systemSystemDetailText systemTabFrontActiveText systemTabFrontInactiveText |
︙ | ︙ | |||
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | systemWhiteText systemWindowBody systemWindowHeaderActiveText systemWindowHeaderBackground systemWindowHeaderInactiveText .DE .RE .TP \fBWindows\fR . On Windows, the following additional system colors are available (note that the actual color values depend on the currently active OS theme): .RS .DS .ta 6c | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 | systemWhiteText systemWindowBody systemWindowHeaderActiveText systemWindowHeaderBackground systemWindowHeaderInactiveText .DE .RE . The second group of MacOS colors below are based on Apple's "semantic" NScolors. On OSX 10.14 (Mojave) and later these colors change value when Dark Mode is enabled. However, the change is only observable when the Apple window manager is drawing to the screen. So the \fBwinfo rgb\fR command will return the color coordinates used in the standard Aqua mode, even if Dark Mode has been selected in the system preferences. The numbered systemWindowBackgroundColors are used in the \fBttk::notebook\fR and \fBttk::labelframe\fR widgets to provide a contrasting background. Each numbered color constrasts with its predecessor. .RS .DS systemControlAccentColor systemControlTextColor systemDisabledControlTextColor systemLabelColor systemSelectedTextBackgroundColor systemSelectedTextColor systemTextBackgroundColor systemTextColor systemWindowBackgroundColor systemWindowBackgroundColor1 systemWindowBackgroundColor2 systemWindowBackgroundColor3 systemWindowBackgroundColor4 systemWindowBackgroundColor5 systemWindowBackgroundColor6 systemWindowBackgroundColor7 .DE .RE .TP \fBWindows\fR . On Windows, the following additional system colors are available (note that the actual color values depend on the currently active OS theme): .RS .DS .ta 6c |
︙ | ︙ |
Changes to doc/photo.n.
︙ | ︙ | |||
547 548 549 550 551 552 553 554 555 556 557 558 559 560 | \fBpng \-alpha\fI alphaValue\fR . The option has effect when reading image data from a file. Specifies an additional alpha filtering for the overall image, which allows the background on which the image is displayed to show through. This usually also has the effect of desaturating the image. The \fIalphaValue\fR must be between 0.0 and 1.0. .VE 8.6 .VS 8.7 .SH "COLOR FORMATS" .PP The default image handler can represent/parse color and alpha values of a pixel in one of the formats listed below. If a color format does not contain transparency information, full opacity is assumed. The | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | \fBpng \-alpha\fI alphaValue\fR . The option has effect when reading image data from a file. Specifies an additional alpha filtering for the overall image, which allows the background on which the image is displayed to show through. This usually also has the effect of desaturating the image. The \fIalphaValue\fR must be between 0.0 and 1.0. .TP \fBsvg \-dpi\fI dpiValue\fB \-scale\fI scaleValue\fB \-unit\fI unitValue\fR . \fIdpiValue\fR is used in conversion between given coordinates and screen resolution. The value must be greater than 0 and the default value is 96. \fIscaleValue\fR is used to scale the resulting image. The value must be greater than 0 and the default value is 1. \fIunitValue\fR is the unit of all coordinates in the SVG data. Available units are px (default, coordinates in pixel), pt (1/72 inch), pc (12 pt), mm , cm and in. The svg format supports a wide range of SVG features, but the full SVG standard is not available, for instance the 'text' feature is missing and silently ignores when reading the SVG data. The supported SVG features are: . .RS \fB elements:\fR g, path, rect, circle, ellipse, line, polyline, polygon, linearGradient, radialGradient, stop, defs, svg, style .PP \fB attributes:\fR width, height, viewBox, preserveAspectRatio with none, xMin, xMid, xMax, yMin, yMid, yMax, slice .PP \fB gradient attributes:\fR gradientUnits with objectBoundingBox, gradientTransform, cx, cy, r fx, fy x1, y1, x2, y2 spreadMethod with pad, reflect or repeat, xlink:href .PP \fB poly attributes: \fR points .PP \fB line attributes: \fR x1, y1, x2, y2 .PP \fB ellipse attributes: \fR cx, cy, rx, ry .PP \fB circle attributes: \fR cx, cy, r .PP \fB rectangle attributes: \fR x, y, width, height, rx, ry .PP \fB path attributes: \fR d with m, M, l, L, h, H, v, V, c, C, s, S, q, Q, t, T, a, A, z, Z .PP \fB style attributes: \fR display with none, visibility, hidden, visible, fill with nonzero and evenodd, opacity, fill-opacity, stroke, stroke-width, stroke-dasharray, stroke-dashoffset, stroke-opacity, stroke-linecap with butt, round and square, stroke-linejoin with miter, round and bevel, stroke-miterlimit fill-rule, font-size, transform with matrix, translate, scale, rotate, skewX and skewY, stop-color, stop-opacity, offset, id, class .RE . Currently only SVG images reading and conversion into (pixel-based format) photos is supported: Tk does not (yet) support bundling photo images in SVG vector graphics. .VE 8.6 .VS 8.7 .SH "COLOR FORMATS" .PP The default image handler can represent/parse color and alpha values of a pixel in one of the formats listed below. If a color format does not contain transparency information, full opacity is assumed. The |
︙ | ︙ |
Changes to doc/ttk_combobox.n.
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 | .PP Dynamic states: \fBdisabled\fP, \fBfocus\fP, \fBpressed\fP, \fBreadonly\fP. .PP \fBTCombobox\fP styling options configurable with \fBttk::style\fP are: .PP \fB\-arrowcolor\fP \fIcolor\fP .br \fB\-background\fP \fIcolor\fP .br \fB\-bordercolor\fP \fIcolor\fP .br \fB\-darkcolor\fP \fIcolor\fP .br | > > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | .PP Dynamic states: \fBdisabled\fP, \fBfocus\fP, \fBpressed\fP, \fBreadonly\fP. .PP \fBTCombobox\fP styling options configurable with \fBttk::style\fP are: .PP \fB\-arrowcolor\fP \fIcolor\fP .br \fB\-arrowsize\fP \fIamount\fP .br \fB\-background\fP \fIcolor\fP .br \fB\-bordercolor\fP \fIcolor\fP .br \fB\-darkcolor\fP \fIcolor\fP .br |
︙ | ︙ |
Changes to doc/ttk_entry.n.
︙ | ︙ | |||
218 219 220 221 222 223 224 | .TP \fIpathName \fBvalidate\fR Force revalidation, independent of the conditions specified by the \fB\-validate\fR option. Returns 0 if validation fails, 1 if it succeeds. Sets or clears the \fBinvalid\fR state accordingly. See \fBVALIDATION\fR below for more details. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | .TP \fIpathName \fBvalidate\fR Force revalidation, independent of the conditions specified by the \fB\-validate\fR option. Returns 0 if validation fails, 1 if it succeeds. Sets or clears the \fBinvalid\fR state accordingly. See \fBVALIDATION\fR below for more details. .PP The entry widget also supports the following generic \fBttk::widget\fR widget subcommands (see \fIttk::widget(n)\fR for details): .DS .ta 5.5c 11c \fBcget\fR \fBconfigure\fR \fBidentify\fR \fBinstate\fR \fBstate\fR \fBxview\fR .DE .SH VALIDATION .PP The \fB\-validate\fR, \fB\-validatecommand\fR, and \fB\-invalidcommand\fR options are used to enable entry widget validation. .SS "VALIDATION MODES" .PP |
︙ | ︙ |
Changes to doc/ttk_scale.n.
︙ | ︙ | |||
89 90 91 92 93 94 95 | \fIpathName \fBcoords \fR?\fIvalue\fR? . Get the coordinates corresponding to \fIvalue\fR, or the coordinates corresponding to the current value of the \fB\-value\fR option if \fIvalue\fR is omitted. .SH "STYLING OPTIONS" .PP | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | \fIpathName \fBcoords \fR?\fIvalue\fR? . Get the coordinates corresponding to \fIvalue\fR, or the coordinates corresponding to the current value of the \fB\-value\fR option if \fIvalue\fR is omitted. .SH "STYLING OPTIONS" .PP The class name for a \fBttk::scale\fP is \fBTScale\fP. .PP Dynamic states: \fBactive\fP. .PP \fBTProgressbar\fP styling options configurable with \fBttk::style\fP are: .PP \fB\-background\fP \fIcolor\fP |
︙ | ︙ |
Changes to doc/ttk_scrollbar.n.
︙ | ︙ | |||
72 73 74 75 76 77 78 | \fIfirst\fR and \fIlast\fR are real fractions between 0 and 1. .TP \fIpathName \fBstate\fR ?\fIstateSpec\fR? Modify or query the widget state; see \fIttk::widget(n)\fR. .SH "INTERNAL COMMANDS" .PP The following widget commands are used internally | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | \fIfirst\fR and \fIlast\fR are real fractions between 0 and 1. .TP \fIpathName \fBstate\fR ?\fIstateSpec\fR? Modify or query the widget state; see \fIttk::widget(n)\fR. .SH "INTERNAL COMMANDS" .PP The following widget commands are used internally by the \fBTScrollbar\fP widget class bindings. .TP \fIpathName \fBdelta \fIdeltaX deltaY\fR Returns a real number indicating the fractional change in the scrollbar setting that corresponds to a given change in thumb position. For example, if the scrollbar is horizontal, the result indicates how much the scrollbar setting must change to move the thumb \fIdeltaX\fR pixels to the right (\fIdeltaY\fR is |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ttk::scrollbar $f.vsb \-orient vertical \-command [list $f.t yview] text $f.t \-xscrollcommand [list $f.hsb set] \-yscrollcommand [list $f.vsb set] grid $f.t \-row 0 \-column 0 \-sticky nsew grid $f.vsb \-row 0 \-column 1 \-sticky nsew grid $f.hsb \-row 1 \-column 0 \-sticky nsew grid columnconfigure $f 0 \-weight 1 grid rowconfigure $f 0 \-weight 1 .CE .SH "STYLING OPTIONS" .PP The class name for a \fBttk::scrollbar\fP is \fBTScrollbar\fP. .PP Dynamic states: \fBactive\fP, \fBdisabled\fP. .PP | > | > | > > | > > | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | ttk::scrollbar $f.vsb \-orient vertical \-command [list $f.t yview] text $f.t \-xscrollcommand [list $f.hsb set] \-yscrollcommand [list $f.vsb set] grid $f.t \-row 0 \-column 0 \-sticky nsew grid $f.vsb \-row 0 \-column 1 \-sticky nsew grid $f.hsb \-row 1 \-column 0 \-sticky nsew grid columnconfigure $f 0 \-weight 1 grid rowconfigure $f 0 \-weight 1 pack $f .CE .SH "STYLING OPTIONS" .PP The class name for a \fBttk::scrollbar\fP is \fBTScrollbar\fP. .PP Dynamic states: \fBactive\fP, \fBdisabled\fP. .PP \fBTScrollbar\fP (or more specifically \fBVertical.TScrollbar\fP and \fBHorizontal.TScrollbar\fP) styling options that are configurable with \fBttk::style\fP are: .PP \fB\-arrowcolor\fP \fIcolor\fP .br \fB\-arrowsize\fP \fIamount\fP .br \fB\-background\fP \fIcolor\fP .br \fB\-bordercolor\fP \fIcolor\fP .br \fB\-darkcolor\fP \fIcolor\fP (color of the dark part of the 3D relief) .br \fB\-foreground\fP \fIcolor\fP .br \fB\-gripcount\fP \fIcount\fP (number of lines on the thumb) .br \fB\-lightcolor\fP \fIcolor\fP (color of the light part of the 3D relief) .br \fB\-troughcolor\fP \fIcolor\fP .PP Some options are only available for specific themes. .PP See the \fBttk::style\fP manual page for information on how to configure ttk styles. |
︙ | ︙ |
Changes to doc/ttk_treeview.n.
︙ | ︙ | |||
384 385 386 387 388 389 390 | .TP \fIpathName \fBtag remove \fItag\fR ?\fIitems\fR? Removes the specified \fItag\fR from each of the listed \fIitems\fR. If \fIitems\fR is omitted, removes \fItag\fR from each item in the tree. If \fItag\fR is not present for a particular item, then the \fB\-tags\fR for that item are unchanged. .RE | | | | | > | < > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | .TP \fIpathName \fBtag remove \fItag\fR ?\fIitems\fR? Removes the specified \fItag\fR from each of the listed \fIitems\fR. If \fIitems\fR is omitted, removes \fItag\fR from each item in the tree. If \fItag\fR is not present for a particular item, then the \fB\-tags\fR for that item are unchanged. .RE .PP The treeview widget also supports the following generic \fBttk::widget\fR widget subcommands (see \fIttk::widget(n)\fR for details): .DS .ta 5.5c 11c \fBxview\fR \fByview\fR .DE .SH "ITEM OPTIONS" .PP The following item options may be specified for items in the \fBinsert\fR and \fBitem\fR widget commands. .OP \-text text Text The textual label to display for the item. .OP \-image image Image |
︙ | ︙ |
Changes to doc/ttk_widget.n.
︙ | ︙ | |||
220 221 222 223 224 225 226 227 228 229 230 231 232 233 | set changes [\fIpathName \fRstate \fIspec\fR] \fIpathName \fRstate $changes .CE will restore \fIpathName\fR to the original state. If \fIstateSpec\fR is not specified, returns a list of the currently-enabled state flags. .RE .SH "WIDGET STATES" The widget state is a bitmap of independent state flags. Widget state flags include: .TP \fBactive\fR . The mouse cursor is over the widget | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | set changes [\fIpathName \fRstate \fIspec\fR] \fIpathName \fRstate $changes .CE will restore \fIpathName\fR to the original state. If \fIstateSpec\fR is not specified, returns a list of the currently-enabled state flags. .RE .TP \fIpathName \fBxview \fIargs\fR This command is used to query and change the horizontal position of the content in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fBxview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the horizontal span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the widget's content is off-screen to the left, the middle 40% is visible in the window, and 40% of the content is off-screen to the right. These are the same values passed to scrollbars via the \fB\-xscrollcommand\fR option. .TP \fIpathName \fBxview\fR \fIindex\fR Adjusts the view in the window so that the content given by \fIindex\fR is displayed at the left edge of the window. .TP \fIpathName \fBxview moveto\fI fraction\fR Adjusts the view in the window so that the character \fIfraction\fR of the way through the content appears at the left edge of the window. \fIFraction\fR must be a fraction between 0 and 1. .TP \fIpathName \fBxview scroll \fInumber what\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. '\" or an abbreviation of one of these, but we don't document that. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right by \fInumber\fR average-width characters on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then characters farther to the left become visible; if it is positive then characters farther to the right become visible. .RE .TP \fIpathName \fByview \fIargs\fR This command is used to query and change the vertical position of the content in the widget's window. It can take any of the following forms: .RS .TP \fIpathName \fByview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the vertical span that is visible in the window. For example, if the first element is .2 and the second element is .6, 20% of the widget's content is off-screen to the top, the middle 40% is visible in the window, and 40% of the content is off-screen to the bottom. These are the same values passed to scrollbars via the \fB\-yscrollcommand\fR option. .TP \fIpathName \fByview\fR \fIindex\fR Adjusts the view in the window so that the content given by \fIindex\fR is displayed at the top edge of the window. .TP \fIpathName \fByview moveto\fI fraction\fR Adjusts the view in the window so that the item \fIfraction\fR of the way through the content appears at the top edge of the window. \fIFraction\fR must be a fraction between 0 and 1. .TP \fIpathName \fByview scroll \fInumber what\fR This command shifts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. '\" or an abbreviation of one of these, but we don't document that. If \fIwhat\fR is \fBunits\fR, the view adjusts up or down by \fInumber\fR average-width characters on the display; if it is \fBpages\fR then the view adjusts by \fInumber\fR screenfuls. If \fInumber\fR is negative then items farther to the top become visible; if it is positive then items farther to the bottom become visible. .RE .SH "WIDGET STATES" The widget state is a bitmap of independent state flags. Widget state flags include: .TP \fBactive\fR . The mouse cursor is over the widget |
︙ | ︙ |
Added generic/nanosvg.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 | /* * Copyright (c) 2013-14 Mikko Mononen [email protected] * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) * * Arc calculation code based on canvg (https://code.google.com/p/canvg/) * * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html * */ #ifndef NANOSVG_H #define NANOSVG_H #ifdef __cplusplus extern "C" { #endif // NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. // // The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. // // NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! // // The shapes in the SVG images are transformed by the viewBox and converted to specified units. // That is, you should get the same looking data as your designed in your favorite app. // // NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose // to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. // // The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. // DPI (dots-per-inch) controls how the unit conversion is done. // // If you don't know or care about the units stuff, "px" and 96 should get you going. /* Example Usage: // Load NSVGImage* image; image = nsvgParseFromFile("test.svg", "px", 96); printf("size: %f x %f\n", image->width, image->height); // Use... for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { for (int i = 0; i < path->npts-1; i += 3) { float* p = &path->pts[i*2]; drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); } } } // Delete nsvgDelete(image); */ #ifndef NANOSVG_SCOPE #define NANOSVG_SCOPE #endif #ifndef NANOSVG_malloc #define NANOSVG_malloc malloc #endif #ifndef NANOSVG_realloc #define NANOSVG_realloc realloc #endif #ifndef NANOSVG_free #define NANOSVG_free free #endif // float emulation for MS VC6++ compiler #if (_MSC_VER == 1200) #define tanf(a) (float)tan(a) #define cosf(a) (float)cos(a) #define sinf(a) (float)sin(a) #define sqrtf(a) (float)sqrt(a) #define fabsf(a) (float)abs(a) #define acosf(a) (float)acos(a) #define atan2f(a,b) (float)atan2(a,b) #define ceilf(a) (float)ceil(a) #define fmodf(a,b) (float)fmod(a,b) #define floorf(a) (float)floor(a) #endif enum NSVGpaintType { NSVG_PAINT_NONE = 0, NSVG_PAINT_COLOR = 1, NSVG_PAINT_LINEAR_GRADIENT = 2, NSVG_PAINT_RADIAL_GRADIENT = 3 }; enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; typedef struct NSVGgradientStop { unsigned int color; float offset; } NSVGgradientStop; typedef struct NSVGgradient { float xform[6]; char spread; float fx, fy; int nstops; NSVGgradientStop stops[1]; } NSVGgradient; typedef struct NSVGpaint { char type; union { unsigned int color; NSVGgradient* gradient; }; } NSVGpaint; typedef struct NSVGpath { float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... int npts; // Total number of bezier points. char closed; // Flag indicating if shapes should be treated as closed. float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. struct NSVGpath* next; // Pointer to next path, or NULL if last element. } NSVGpath; typedef struct NSVGshape { char id[64]; // Optional 'id' attr of the shape or its group NSVGpaint fill; // Fill paint NSVGpaint stroke; // Stroke paint float opacity; // Opacity of the shape. float strokeWidth; // Stroke width (scaled). float strokeDashOffset; // Stroke dash offset (scaled). float strokeDashArray[8]; // Stroke dash array (scaled). char strokeDashCount; // Number of dash values in dash array. char strokeLineJoin; // Stroke join type. char strokeLineCap; // Stroke cap type. float miterLimit; // Miter limit char fillRule; // Fill rule, see NSVGfillRule. unsigned char flags; // Logical or of NSVG_FLAGS_* flags float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. NSVGpath* paths; // Linked list of paths in the image. struct NSVGshape* next; // Pointer to next shape, or NULL if last element. } NSVGshape; typedef struct NSVGimage { float width; // Width of the image. float height; // Height of the image. NSVGshape* shapes; // Linked list of shapes in the image. } NSVGimage; // Parses SVG file from a file, returns SVG image as paths. NANOSVG_SCOPE NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); // Parses SVG file from a null terminated string, returns SVG image as paths. // Important note: changes the string. NANOSVG_SCOPE NSVGimage* nsvgParse(char* input, const char* units, float dpi); // Deletes list of paths. NANOSVG_SCOPE void nsvgDelete(NSVGimage* image); #ifdef __cplusplus } #endif #endif // NANOSVG_H #ifdef NANOSVG_IMPLEMENTATION #include <string.h> #include <stdlib.h> #include <math.h> #define NSVG_PI (3.14159265358979323846264338327f) #define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. #define NSVG_ALIGN_MIN 0 #define NSVG_ALIGN_MID 1 #define NSVG_ALIGN_MAX 2 #define NSVG_ALIGN_NONE 0 #define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 #define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) #ifdef _MSC_VER #pragma warning (disable: 4996) // Switch off security warnings #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings #ifdef __cplusplus #define NSVG_INLINE inline #else #define NSVG_INLINE #endif #if !defined(strtoll) // old MSVC versions do not have strtoll() #define strtoll _strtoi64 #endif #else #define NSVG_INLINE inline #endif static int nsvg__isspace(char c) { return strchr(" \t\n\v\f\r", c) != 0; } static int nsvg__isdigit(char c) { return c >= '0' && c <= '9'; } static int nsvg__isnum(char c) { return strchr("0123456789+-.eE", c) != 0; } static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } // Simple XML parser #define NSVG_XML_TAG 1 #define NSVG_XML_CONTENT 2 #define NSVG_XML_MAX_ATTRIBS 256 static void nsvg__parseContent(char* s, void (*contentCb)(void* ud, const char* s), void* ud) { // Trim start white spaces while (*s && nsvg__isspace(*s)) s++; if (!*s) return; if (contentCb) (*contentCb)(ud, s); } static void nsvg__parseElement(char* s, void (*startelCb)(void* ud, const char* el, const char** attr), void (*endelCb)(void* ud, const char* el), void* ud) { const char* attr[NSVG_XML_MAX_ATTRIBS]; int nattr = 0; char* name; int start = 0; int end = 0; char quote; // Skip white space after the '<' while (*s && nsvg__isspace(*s)) s++; // Check if the tag is end tag if (*s == '/') { s++; end = 1; } else { start = 1; } // Skip comments, data and preprocessor stuff. if (!*s || *s == '?' || *s == '!') return; // Get tag name name = s; while (*s && !nsvg__isspace(*s)) s++; if (*s) { *s++ = '\0'; } // Get attribs while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { char* name = NULL; char* value = NULL; // Skip white space before the attrib name while (*s && nsvg__isspace(*s)) s++; if (!*s) break; if (*s == '/') { end = 1; break; } name = s; // Find end of the attrib name. while (*s && !nsvg__isspace(*s) && *s != '=') s++; if (*s) { *s++ = '\0'; } // Skip until the beginning of the value. while (*s && *s != '\"' && *s != '\'') s++; if (!*s) break; quote = *s; s++; // Store value and find the end of it. value = s; while (*s && *s != quote) s++; if (*s) { *s++ = '\0'; } // Store only well formed attributes if (name && value) { attr[nattr++] = name; attr[nattr++] = value; } } // List terminator attr[nattr++] = 0; attr[nattr++] = 0; // Call callbacks. if (start && startelCb) (*startelCb)(ud, name, attr); if (end && endelCb) (*endelCb)(ud, name); } NANOSVG_SCOPE int nsvg__parseXML(char* input, void (*startelCb)(void* ud, const char* el, const char** attr), void (*endelCb)(void* ud, const char* el), void (*contentCb)(void* ud, const char* s), void* ud) { char* s = input; char* mark = s; int state = NSVG_XML_CONTENT; while (*s) { if (*s == '<' && state == NSVG_XML_CONTENT) { // Start of a tag *s++ = '\0'; nsvg__parseContent(mark, contentCb, ud); mark = s; state = NSVG_XML_TAG; } else if (*s == '>' && state == NSVG_XML_TAG) { // Start of a content or new tag. *s++ = '\0'; nsvg__parseContent(mark, contentCb, ud); nsvg__parseElement(mark, startelCb, endelCb, ud); mark = s; state = NSVG_XML_CONTENT; } else { s++; } } return 1; } /* Simple SVG parser. */ #define NSVG_MAX_ATTR 128 enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; #define NSVG_MAX_DASHES 8 enum NSVGunits { NSVG_UNITS_USER, NSVG_UNITS_PX, NSVG_UNITS_PT, NSVG_UNITS_PC, NSVG_UNITS_MM, NSVG_UNITS_CM, NSVG_UNITS_IN, NSVG_UNITS_PERCENT, NSVG_UNITS_EM, NSVG_UNITS_EX }; enum NSVGvisible { NSVG_VIS_DISPLAY = 1, NSVG_VIS_VISIBLE = 2 }; typedef struct NSVGcoordinate { float value; int units; } NSVGcoordinate; typedef struct NSVGlinearData { NSVGcoordinate x1, y1, x2, y2; } NSVGlinearData; typedef struct NSVGradialData { NSVGcoordinate cx, cy, r, fx, fy; } NSVGradialData; typedef struct NSVGgradientData { char id[64]; char ref[64]; char type; union { NSVGlinearData linear; NSVGradialData radial; }; char spread; char units; float xform[6]; int nstops; NSVGgradientStop* stops; struct NSVGgradientData* next; } NSVGgradientData; typedef struct NSVGattrib { char id[64]; float xform[6]; unsigned int fillColor; unsigned int strokeColor; float opacity; float fillOpacity; float strokeOpacity; char fillGradient[64]; char strokeGradient[64]; float strokeWidth; float strokeDashOffset; float strokeDashArray[NSVG_MAX_DASHES]; int strokeDashCount; char strokeLineJoin; char strokeLineCap; float miterLimit; char fillRule; float fontSize; unsigned int stopColor; float stopOpacity; float stopOffset; char hasFill; char hasStroke; char visible; } NSVGattrib; typedef struct NSVGstyles { char* name; char* description; struct NSVGstyles* next; } NSVGstyles; typedef struct NSVGparser { NSVGattrib attr[NSVG_MAX_ATTR]; int attrHead; float* pts; int npts; int cpts; NSVGpath* plist; NSVGimage* image; NSVGstyles* styles; NSVGgradientData* gradients; NSVGshape* shapesTail; float viewMinx, viewMiny, viewWidth, viewHeight; int alignX, alignY, alignType; float dpi; char pathFlag; char defsFlag; char styleFlag; } NSVGparser; static void nsvg__xformIdentity(float* t) { t[0] = 1.0f; t[1] = 0.0f; t[2] = 0.0f; t[3] = 1.0f; t[4] = 0.0f; t[5] = 0.0f; } static void nsvg__xformSetTranslation(float* t, float tx, float ty) { t[0] = 1.0f; t[1] = 0.0f; t[2] = 0.0f; t[3] = 1.0f; t[4] = tx; t[5] = ty; } static void nsvg__xformSetScale(float* t, float sx, float sy) { t[0] = sx; t[1] = 0.0f; t[2] = 0.0f; t[3] = sy; t[4] = 0.0f; t[5] = 0.0f; } static void nsvg__xformSetSkewX(float* t, float a) { t[0] = 1.0f; t[1] = 0.0f; t[2] = tanf(a); t[3] = 1.0f; t[4] = 0.0f; t[5] = 0.0f; } static void nsvg__xformSetSkewY(float* t, float a) { t[0] = 1.0f; t[1] = tanf(a); t[2] = 0.0f; t[3] = 1.0f; t[4] = 0.0f; t[5] = 0.0f; } static void nsvg__xformSetRotation(float* t, float a) { float cs = cosf(a), sn = sinf(a); t[0] = cs; t[1] = sn; t[2] = -sn; t[3] = cs; t[4] = 0.0f; t[5] = 0.0f; } static void nsvg__xformMultiply(float* t, float* s) { float t0 = t[0] * s[0] + t[1] * s[2]; float t2 = t[2] * s[0] + t[3] * s[2]; float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; t[1] = t[0] * s[1] + t[1] * s[3]; t[3] = t[2] * s[1] + t[3] * s[3]; t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; t[0] = t0; t[2] = t2; t[4] = t4; } static void nsvg__xformInverse(float* inv, float* t) { double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; if (det > -1e-6 && det < 1e-6) { nsvg__xformIdentity(t); return; } invdet = 1.0 / det; inv[0] = (float)(t[3] * invdet); inv[2] = (float)(-t[2] * invdet); inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); inv[1] = (float)(-t[1] * invdet); inv[3] = (float)(t[0] * invdet); inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); } static void nsvg__xformPremultiply(float* t, float* s) { float s2[6]; memcpy(s2, s, sizeof(float)*6); nsvg__xformMultiply(s2, t); memcpy(t, s2, sizeof(float)*6); } static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) { *dx = x*t[0] + y*t[2] + t[4]; *dy = x*t[1] + y*t[3] + t[5]; } static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) { *dx = x*t[0] + y*t[2]; *dy = x*t[1] + y*t[3]; } #define NSVG_EPSILON (1e-12) static int nsvg__ptInBounds(float* pt, float* bounds) { return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; } static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) { double it = 1.0-t; return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; } static void nsvg__curveBounds(float* bounds, float* curve) { int i, j, count; double roots[2], a, b, c, b2ac, t, v; float* v0 = &curve[0]; float* v1 = &curve[2]; float* v2 = &curve[4]; float* v3 = &curve[6]; // Start the bounding box by end points bounds[0] = nsvg__minf(v0[0], v3[0]); bounds[1] = nsvg__minf(v0[1], v3[1]); bounds[2] = nsvg__maxf(v0[0], v3[0]); bounds[3] = nsvg__maxf(v0[1], v3[1]); // Bezier curve fits inside the convex hull of it's control points. // If control points are inside the bounds, we're done. if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) return; // Add bezier curve inflection points in X and Y. for (i = 0; i < 2; i++) { a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; c = 3.0 * v1[i] - 3.0 * v0[i]; count = 0; if (fabs(a) < NSVG_EPSILON) { if (fabs(b) > NSVG_EPSILON) { t = -c / b; if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) roots[count++] = t; } } else { b2ac = b*b - 4.0*c*a; if (b2ac > NSVG_EPSILON) { t = (-b + sqrt(b2ac)) / (2.0 * a); if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) roots[count++] = t; t = (-b - sqrt(b2ac)) / (2.0 * a); if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) roots[count++] = t; } } for (j = 0; j < count; j++) { v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); } } } static NSVGparser* nsvg__createParser() { NSVGparser* p; p = (NSVGparser*)NANOSVG_malloc(sizeof(NSVGparser)); if (p == NULL) goto error; memset(p, 0, sizeof(NSVGparser)); p->image = (NSVGimage*)NANOSVG_malloc(sizeof(NSVGimage)); if (p->image == NULL) goto error; memset(p->image, 0, sizeof(NSVGimage)); // Init style nsvg__xformIdentity(p->attr[0].xform); memset(p->attr[0].id, 0, sizeof p->attr[0].id); p->attr[0].fillColor = NSVG_RGB(0,0,0); p->attr[0].strokeColor = NSVG_RGB(0,0,0); p->attr[0].opacity = 1; p->attr[0].fillOpacity = 1; p->attr[0].strokeOpacity = 1; p->attr[0].stopOpacity = 1; p->attr[0].strokeWidth = 1; p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; p->attr[0].strokeLineCap = NSVG_CAP_BUTT; p->attr[0].miterLimit = 4; p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; p->attr[0].hasFill = 1; p->attr[0].visible = NSVG_VIS_DISPLAY | NSVG_VIS_VISIBLE; return p; error: if (p) { if (p->image) NANOSVG_free(p->image); NANOSVG_free(p); } return NULL; } static void nsvg__deleteStyles(NSVGstyles* style) { while (style) { NSVGstyles *next = style->next; if (style->name!= NULL) free(style->name); if (style->description != NULL) free(style->description); free(style); style = next; } } static void nsvg__deletePaths(NSVGpath* path) { while (path) { NSVGpath *next = path->next; if (path->pts != NULL) NANOSVG_free(path->pts); NANOSVG_free(path); path = next; } } static void nsvg__deletePaint(NSVGpaint* paint) { if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) NANOSVG_free(paint->gradient); } static void nsvg__deleteGradientData(NSVGgradientData* grad) { NSVGgradientData* next; while (grad != NULL) { next = grad->next; NANOSVG_free(grad->stops); NANOSVG_free(grad); grad = next; } } static void nsvg__deleteParser(NSVGparser* p) { if (p != NULL) { nsvg__deleteStyles(p->styles); nsvg__deletePaths(p->plist); nsvg__deleteGradientData(p->gradients); nsvgDelete(p->image); NANOSVG_free(p->pts); NANOSVG_free(p); } } static void nsvg__resetPath(NSVGparser* p) { p->npts = 0; } static void nsvg__addPoint(NSVGparser* p, float x, float y) { if (p->npts+1 > p->cpts) { p->cpts = p->cpts ? p->cpts*2 : 8; p->pts = (float*)NANOSVG_realloc(p->pts, p->cpts*2*sizeof(float)); if (!p->pts) return; } p->pts[p->npts*2+0] = x; p->pts[p->npts*2+1] = y; p->npts++; } static void nsvg__moveTo(NSVGparser* p, float x, float y) { if (p->npts > 0) { p->pts[(p->npts-1)*2+0] = x; p->pts[(p->npts-1)*2+1] = y; } else { nsvg__addPoint(p, x, y); } } static void nsvg__lineTo(NSVGparser* p, float x, float y) { float px,py, dx,dy; if (p->npts > 0) { px = p->pts[(p->npts-1)*2+0]; py = p->pts[(p->npts-1)*2+1]; dx = x - px; dy = y - py; nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); nsvg__addPoint(p, x, y); } } static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) { nsvg__addPoint(p, cpx1, cpy1); nsvg__addPoint(p, cpx2, cpy2); nsvg__addPoint(p, x, y); } static NSVGattrib* nsvg__getAttr(NSVGparser* p) { return &p->attr[p->attrHead]; } static void nsvg__pushAttr(NSVGparser* p) { if (p->attrHead < NSVG_MAX_ATTR-1) { p->attrHead++; memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); } } static void nsvg__popAttr(NSVGparser* p) { if (p->attrHead > 0) p->attrHead--; } static float nsvg__actualOrigX(NSVGparser* p) { return p->viewMinx; } static float nsvg__actualOrigY(NSVGparser* p) { return p->viewMiny; } static float nsvg__actualWidth(NSVGparser* p) { return p->viewWidth; } static float nsvg__actualHeight(NSVGparser* p) { return p->viewHeight; } static float nsvg__actualLength(NSVGparser* p) { float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); return sqrtf(w*w + h*h) / sqrtf(2.0f); } static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) { NSVGattrib* attr = nsvg__getAttr(p); switch (c.units) { case NSVG_UNITS_USER: return c.value; case NSVG_UNITS_PX: return c.value; case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; case NSVG_UNITS_IN: return c.value * p->dpi; case NSVG_UNITS_EM: return c.value * attr->fontSize; case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; default: return c.value; } return c.value; } static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) { NSVGgradientData* grad = p->gradients; while (grad) { if (strcmp(grad->id, id) == 0) return grad; grad = grad->next; } return NULL; } static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) { NSVGattrib* attr = nsvg__getAttr(p); NSVGgradientData* data = NULL; NSVGgradientData* ref = NULL; NSVGgradientStop* stops = NULL; NSVGgradient* grad; float ox, oy, sw, sh, sl; int nstops = 0; data = nsvg__findGradientData(p, id); if (data == NULL) return NULL; // TODO: use ref to fill in all unset values too. ref = data; while (ref != NULL) { if (stops == NULL && ref->stops != NULL) { stops = ref->stops; nstops = ref->nstops; break; } ref = nsvg__findGradientData(p, ref->ref); } if (stops == NULL) return NULL; grad = (NSVGgradient*)NANOSVG_malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); if (grad == NULL) return NULL; // The shape width and height. if (data->units == NSVG_OBJECT_SPACE) { ox = localBounds[0]; oy = localBounds[1]; sw = localBounds[2] - localBounds[0]; sh = localBounds[3] - localBounds[1]; } else { ox = nsvg__actualOrigX(p); oy = nsvg__actualOrigY(p); sw = nsvg__actualWidth(p); sh = nsvg__actualHeight(p); } sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { float x1, y1, x2, y2, dx, dy; x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); // Calculate transform aligned to the line dx = x2 - x1; dy = y2 - y1; grad->xform[0] = dy; grad->xform[1] = -dx; grad->xform[2] = dx; grad->xform[3] = dy; grad->xform[4] = x1; grad->xform[5] = y1; } else { float cx, cy, fx, fy, r; cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); r = nsvg__convertToPixels(p, data->radial.r, 0, sl); // Calculate transform aligned to the circle grad->xform[0] = r; grad->xform[1] = 0; grad->xform[2] = 0; grad->xform[3] = r; grad->xform[4] = cx; grad->xform[5] = cy; grad->fx = fx / r; grad->fy = fy / r; } nsvg__xformMultiply(grad->xform, data->xform); nsvg__xformMultiply(grad->xform, attr->xform); grad->spread = data->spread; memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); grad->nstops = nstops; *paintType = data->type; return grad; } static float nsvg__getAverageScale(float* t) { float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); return (sx + sy) * 0.5f; } static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) { NSVGpath* path; float curve[4*2], curveBounds[4]; int i, first = 1; for (path = shape->paths; path != NULL; path = path->next) { nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); for (i = 0; i < path->npts-1; i += 3) { nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); nsvg__curveBounds(curveBounds, curve); if (first) { bounds[0] = curveBounds[0]; bounds[1] = curveBounds[1]; bounds[2] = curveBounds[2]; bounds[3] = curveBounds[3]; first = 0; } else { bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); } curve[0] = curve[6]; curve[1] = curve[7]; } } } static void nsvg__addShape(NSVGparser* p) { NSVGattrib* attr = nsvg__getAttr(p); float scale = 1.0f; NSVGshape* shape; NSVGpath* path; int i; if (p->plist == NULL) return; shape = (NSVGshape*)NANOSVG_malloc(sizeof(NSVGshape)); if (shape == NULL) goto error; memset(shape, 0, sizeof(NSVGshape)); memcpy(shape->id, attr->id, sizeof shape->id); scale = nsvg__getAverageScale(attr->xform); shape->strokeWidth = attr->strokeWidth * scale; shape->strokeDashOffset = attr->strokeDashOffset * scale; shape->strokeDashCount = (char)attr->strokeDashCount; for (i = 0; i < attr->strokeDashCount; i++) shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; shape->strokeLineJoin = attr->strokeLineJoin; shape->strokeLineCap = attr->strokeLineCap; shape->miterLimit = attr->miterLimit; shape->fillRule = attr->fillRule; shape->opacity = attr->opacity; shape->paths = p->plist; p->plist = NULL; // Calculate shape bounds shape->bounds[0] = shape->paths->bounds[0]; shape->bounds[1] = shape->paths->bounds[1]; shape->bounds[2] = shape->paths->bounds[2]; shape->bounds[3] = shape->paths->bounds[3]; for (path = shape->paths->next; path != NULL; path = path->next) { shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); } // Set fill if (attr->hasFill == 0) { shape->fill.type = NSVG_PAINT_NONE; } else if (attr->hasFill == 1) { shape->fill.type = NSVG_PAINT_COLOR; shape->fill.color = attr->fillColor; shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; } else if (attr->hasFill == 2) { float inv[6], localBounds[4]; nsvg__xformInverse(inv, attr->xform); nsvg__getLocalBounds(localBounds, shape, inv); shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); if (shape->fill.gradient == NULL) { shape->fill.type = NSVG_PAINT_NONE; } } // Set stroke if (attr->hasStroke == 0) { shape->stroke.type = NSVG_PAINT_NONE; } else if (attr->hasStroke == 1) { shape->stroke.type = NSVG_PAINT_COLOR; shape->stroke.color = attr->strokeColor; shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; } else if (attr->hasStroke == 2) { float inv[6], localBounds[4]; nsvg__xformInverse(inv, attr->xform); nsvg__getLocalBounds(localBounds, shape, inv); shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); if (shape->stroke.gradient == NULL) shape->stroke.type = NSVG_PAINT_NONE; } // Set flags shape->flags = ((attr->visible & NSVG_VIS_DISPLAY) && (attr->visible & NSVG_VIS_VISIBLE) ? NSVG_FLAGS_VISIBLE : 0x00); // Add to tail if (p->image->shapes == NULL) p->image->shapes = shape; else p->shapesTail->next = shape; p->shapesTail = shape; return; error: if (shape) NANOSVG_free(shape); } static void nsvg__addPath(NSVGparser* p, char closed) { NSVGattrib* attr = nsvg__getAttr(p); NSVGpath* path = NULL; float bounds[4]; float* curve; int i; if (p->npts < 4) return; if (closed) nsvg__lineTo(p, p->pts[0], p->pts[1]); path = (NSVGpath*)NANOSVG_malloc(sizeof(NSVGpath)); if (path == NULL) goto error; memset(path, 0, sizeof(NSVGpath)); path->pts = (float*)NANOSVG_malloc(p->npts*2*sizeof(float)); if (path->pts == NULL) goto error; path->closed = closed; path->npts = p->npts; // Transform path. for (i = 0; i < p->npts; ++i) nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); // Find bounds for (i = 0; i < path->npts-1; i += 3) { curve = &path->pts[i*2]; nsvg__curveBounds(bounds, curve); if (i == 0) { path->bounds[0] = bounds[0]; path->bounds[1] = bounds[1]; path->bounds[2] = bounds[2]; path->bounds[3] = bounds[3]; } else { path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); } } path->next = p->plist; p->plist = path; return; error: if (path != NULL) { if (path->pts != NULL) NANOSVG_free(path->pts); NANOSVG_free(path); } } // We roll our own string to float because the std library one uses locale and messes things up. static double nsvg__atof(const char* s) { char* cur = (char*)s; char* end = NULL; double res = 0.0, sign = 1.0; #if (_MSC_VER == 1200) __int64 intPart = 0, fracPart = 0; #else long long intPart = 0, fracPart = 0; #endif char hasIntPart = 0, hasFracPart = 0; // Parse optional sign if (*cur == '+') { cur++; } else if (*cur == '-') { sign = -1; cur++; } // Parse integer part if (nsvg__isdigit(*cur)) { // Parse digit sequence #if (_MSC_VER == 1200) intPart = strtol(cur, &end, 10); #else intPart = strtoll(cur, &end, 10); #endif if (cur != end) { res = (double)intPart; hasIntPart = 1; cur = end; } } // Parse fractional part. if (*cur == '.') { cur++; // Skip '.' if (nsvg__isdigit(*cur)) { // Parse digit sequence #if (_MSC_VER == 1200) fracPart = strtol(cur, &end, 10); #else fracPart = strtoll(cur, &end, 10); #endif if (cur != end) { res += (double)fracPart / pow(10.0, (double)(end - cur)); hasFracPart = 1; cur = end; } } } // A valid number should have integer or fractional part. if (!hasIntPart && !hasFracPart) return 0.0; // Parse optional exponent if (*cur == 'e' || *cur == 'E') { int expPart = 0; cur++; // skip 'E' expPart = strtol(cur, &end, 10); // Parse digit sequence with sign if (cur != end) { res *= pow(10.0, (double)expPart); } } return res * sign; } static const char* nsvg__parseNumber(const char* s, char* it, const int size) { const int last = size-1; int i = 0; // sign if (*s == '-' || *s == '+') { if (i < last) it[i++] = *s; s++; } // integer part while (*s && nsvg__isdigit(*s)) { if (i < last) it[i++] = *s; s++; } if (*s == '.') { // decimal point if (i < last) it[i++] = *s; s++; // fraction part while (*s && nsvg__isdigit(*s)) { if (i < last) it[i++] = *s; s++; } } // exponent if (*s == 'e' || *s == 'E') { if (i < last) it[i++] = *s; s++; if (*s == '-' || *s == '+') { if (i < last) it[i++] = *s; s++; } while (*s && nsvg__isdigit(*s)) { if (i < last) it[i++] = *s; s++; } } it[i] = '\0'; return s; } static const char* nsvg__getNextPathItem(const char* s, char* it) { it[0] = '\0'; // Skip white spaces and commas while (*s && (nsvg__isspace(*s) || *s == ',')) s++; if (!*s) return s; if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { s = nsvg__parseNumber(s, it, 64); } else { // Parse command it[0] = *s++; it[1] = '\0'; return s; } return s; } static unsigned int nsvg__parseColorHex(const char* str) { unsigned int c = 0, r = 0, g = 0, b = 0; int n = 0; str++; // skip # // Calculate number of characters. while(str[n] && !nsvg__isspace(str[n])) n++; if (n == 6) { sscanf(str, "%x", &c); } else if (n == 3) { sscanf(str, "%x", &c); c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); c |= c<<4; } r = (c >> 16) & 0xff; g = (c >> 8) & 0xff; b = c & 0xff; return NSVG_RGB(r,g,b); } static unsigned int nsvg__parseColorRGB(const char* str) { int r = -1, g = -1, b = -1; char s1[32]="", s2[32]=""; sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); if (strchr(s1, '%')) { return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); } else { return NSVG_RGB(r,g,b); } } typedef struct NSVGNamedColor { const char* name; unsigned int color; } NSVGNamedColor; NSVGNamedColor nsvg__colors[] = { { "red", NSVG_RGB(255, 0, 0) }, { "green", NSVG_RGB( 0, 128, 0) }, { "blue", NSVG_RGB( 0, 0, 255) }, { "yellow", NSVG_RGB(255, 255, 0) }, { "cyan", NSVG_RGB( 0, 255, 255) }, { "magenta", NSVG_RGB(255, 0, 255) }, { "black", NSVG_RGB( 0, 0, 0) }, { "grey", NSVG_RGB(128, 128, 128) }, { "gray", NSVG_RGB(128, 128, 128) }, { "white", NSVG_RGB(255, 255, 255) }, #ifdef NANOSVG_ALL_COLOR_KEYWORDS { "aliceblue", NSVG_RGB(240, 248, 255) }, { "antiquewhite", NSVG_RGB(250, 235, 215) }, { "aqua", NSVG_RGB( 0, 255, 255) }, { "aquamarine", NSVG_RGB(127, 255, 212) }, { "azure", NSVG_RGB(240, 255, 255) }, { "beige", NSVG_RGB(245, 245, 220) }, { "bisque", NSVG_RGB(255, 228, 196) }, { "blanchedalmond", NSVG_RGB(255, 235, 205) }, { "blueviolet", NSVG_RGB(138, 43, 226) }, { "brown", NSVG_RGB(165, 42, 42) }, { "burlywood", NSVG_RGB(222, 184, 135) }, { "cadetblue", NSVG_RGB( 95, 158, 160) }, { "chartreuse", NSVG_RGB(127, 255, 0) }, { "chocolate", NSVG_RGB(210, 105, 30) }, { "coral", NSVG_RGB(255, 127, 80) }, { "cornflowerblue", NSVG_RGB(100, 149, 237) }, { "cornsilk", NSVG_RGB(255, 248, 220) }, { "crimson", NSVG_RGB(220, 20, 60) }, { "darkblue", NSVG_RGB( 0, 0, 139) }, { "darkcyan", NSVG_RGB( 0, 139, 139) }, { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, { "darkgray", NSVG_RGB(169, 169, 169) }, { "darkgreen", NSVG_RGB( 0, 100, 0) }, { "darkgrey", NSVG_RGB(169, 169, 169) }, { "darkkhaki", NSVG_RGB(189, 183, 107) }, { "darkmagenta", NSVG_RGB(139, 0, 139) }, { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, { "darkorange", NSVG_RGB(255, 140, 0) }, { "darkorchid", NSVG_RGB(153, 50, 204) }, { "darkred", NSVG_RGB(139, 0, 0) }, { "darksalmon", NSVG_RGB(233, 150, 122) }, { "darkseagreen", NSVG_RGB(143, 188, 143) }, { "darkslateblue", NSVG_RGB( 72, 61, 139) }, { "darkslategray", NSVG_RGB( 47, 79, 79) }, { "darkslategrey", NSVG_RGB( 47, 79, 79) }, { "darkturquoise", NSVG_RGB( 0, 206, 209) }, { "darkviolet", NSVG_RGB(148, 0, 211) }, { "deeppink", NSVG_RGB(255, 20, 147) }, { "deepskyblue", NSVG_RGB( 0, 191, 255) }, { "dimgray", NSVG_RGB(105, 105, 105) }, { "dimgrey", NSVG_RGB(105, 105, 105) }, { "dodgerblue", NSVG_RGB( 30, 144, 255) }, { "firebrick", NSVG_RGB(178, 34, 34) }, { "floralwhite", NSVG_RGB(255, 250, 240) }, { "forestgreen", NSVG_RGB( 34, 139, 34) }, { "fuchsia", NSVG_RGB(255, 0, 255) }, { "gainsboro", NSVG_RGB(220, 220, 220) }, { "ghostwhite", NSVG_RGB(248, 248, 255) }, { "gold", NSVG_RGB(255, 215, 0) }, { "goldenrod", NSVG_RGB(218, 165, 32) }, { "greenyellow", NSVG_RGB(173, 255, 47) }, { "honeydew", NSVG_RGB(240, 255, 240) }, { "hotpink", NSVG_RGB(255, 105, 180) }, { "indianred", NSVG_RGB(205, 92, 92) }, { "indigo", NSVG_RGB( 75, 0, 130) }, { "ivory", NSVG_RGB(255, 255, 240) }, { "khaki", NSVG_RGB(240, 230, 140) }, { "lavender", NSVG_RGB(230, 230, 250) }, { "lavenderblush", NSVG_RGB(255, 240, 245) }, { "lawngreen", NSVG_RGB(124, 252, 0) }, { "lemonchiffon", NSVG_RGB(255, 250, 205) }, { "lightblue", NSVG_RGB(173, 216, 230) }, { "lightcoral", NSVG_RGB(240, 128, 128) }, { "lightcyan", NSVG_RGB(224, 255, 255) }, { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, { "lightgray", NSVG_RGB(211, 211, 211) }, { "lightgreen", NSVG_RGB(144, 238, 144) }, { "lightgrey", NSVG_RGB(211, 211, 211) }, { "lightpink", NSVG_RGB(255, 182, 193) }, { "lightsalmon", NSVG_RGB(255, 160, 122) }, { "lightseagreen", NSVG_RGB( 32, 178, 170) }, { "lightskyblue", NSVG_RGB(135, 206, 250) }, { "lightslategray", NSVG_RGB(119, 136, 153) }, { "lightslategrey", NSVG_RGB(119, 136, 153) }, { "lightsteelblue", NSVG_RGB(176, 196, 222) }, { "lightyellow", NSVG_RGB(255, 255, 224) }, { "lime", NSVG_RGB( 0, 255, 0) }, { "limegreen", NSVG_RGB( 50, 205, 50) }, { "linen", NSVG_RGB(250, 240, 230) }, { "maroon", NSVG_RGB(128, 0, 0) }, { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, { "mediumblue", NSVG_RGB( 0, 0, 205) }, { "mediumorchid", NSVG_RGB(186, 85, 211) }, { "mediumpurple", NSVG_RGB(147, 112, 219) }, { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, { "mediumslateblue", NSVG_RGB(123, 104, 238) }, { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, { "mediumvioletred", NSVG_RGB(199, 21, 133) }, { "midnightblue", NSVG_RGB( 25, 25, 112) }, { "mintcream", NSVG_RGB(245, 255, 250) }, { "mistyrose", NSVG_RGB(255, 228, 225) }, { "moccasin", NSVG_RGB(255, 228, 181) }, { "navajowhite", NSVG_RGB(255, 222, 173) }, { "navy", NSVG_RGB( 0, 0, 128) }, { "oldlace", NSVG_RGB(253, 245, 230) }, { "olive", NSVG_RGB(128, 128, 0) }, { "olivedrab", NSVG_RGB(107, 142, 35) }, { "orange", NSVG_RGB(255, 165, 0) }, { "orangered", NSVG_RGB(255, 69, 0) }, { "orchid", NSVG_RGB(218, 112, 214) }, { "palegoldenrod", NSVG_RGB(238, 232, 170) }, { "palegreen", NSVG_RGB(152, 251, 152) }, { "paleturquoise", NSVG_RGB(175, 238, 238) }, { "palevioletred", NSVG_RGB(219, 112, 147) }, { "papayawhip", NSVG_RGB(255, 239, 213) }, { "peachpuff", NSVG_RGB(255, 218, 185) }, { "peru", NSVG_RGB(205, 133, 63) }, { "pink", NSVG_RGB(255, 192, 203) }, { "plum", NSVG_RGB(221, 160, 221) }, { "powderblue", NSVG_RGB(176, 224, 230) }, { "purple", NSVG_RGB(128, 0, 128) }, { "rosybrown", NSVG_RGB(188, 143, 143) }, { "royalblue", NSVG_RGB( 65, 105, 225) }, { "saddlebrown", NSVG_RGB(139, 69, 19) }, { "salmon", NSVG_RGB(250, 128, 114) }, { "sandybrown", NSVG_RGB(244, 164, 96) }, { "seagreen", NSVG_RGB( 46, 139, 87) }, { "seashell", NSVG_RGB(255, 245, 238) }, { "sienna", NSVG_RGB(160, 82, 45) }, { "silver", NSVG_RGB(192, 192, 192) }, { "skyblue", NSVG_RGB(135, 206, 235) }, { "slateblue", NSVG_RGB(106, 90, 205) }, { "slategray", NSVG_RGB(112, 128, 144) }, { "slategrey", NSVG_RGB(112, 128, 144) }, { "snow", NSVG_RGB(255, 250, 250) }, { "springgreen", NSVG_RGB( 0, 255, 127) }, { "steelblue", NSVG_RGB( 70, 130, 180) }, { "tan", NSVG_RGB(210, 180, 140) }, { "teal", NSVG_RGB( 0, 128, 128) }, { "thistle", NSVG_RGB(216, 191, 216) }, { "tomato", NSVG_RGB(255, 99, 71) }, { "turquoise", NSVG_RGB( 64, 224, 208) }, { "violet", NSVG_RGB(238, 130, 238) }, { "wheat", NSVG_RGB(245, 222, 179) }, { "whitesmoke", NSVG_RGB(245, 245, 245) }, { "yellowgreen", NSVG_RGB(154, 205, 50) }, #endif }; static unsigned int nsvg__parseColorName(const char* str) { int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); for (i = 0; i < ncolors; i++) { if (strcmp(nsvg__colors[i].name, str) == 0) { return nsvg__colors[i].color; } } return NSVG_RGB(128, 128, 128); } static unsigned int nsvg__parseColor(const char* str) { size_t len = 0; while(*str == ' ') ++str; len = strlen(str); if (len >= 1 && *str == '#') return nsvg__parseColorHex(str); else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') return nsvg__parseColorRGB(str); return nsvg__parseColorName(str); } static float nsvg__parseOpacity(const char* str) { float val = 0; sscanf(str, "%f", &val); if (val < 0.0f) val = 0.0f; if (val > 1.0f) val = 1.0f; return val; } static float nsvg__parseMiterLimit(const char* str) { float val = 0; sscanf(str, "%f", &val); if (val < 0.0f) val = 0.0f; return val; } static int nsvg__parseUnits(const char* units) { if (units[0] == 'p' && units[1] == 'x') return NSVG_UNITS_PX; else if (units[0] == 'p' && units[1] == 't') return NSVG_UNITS_PT; else if (units[0] == 'p' && units[1] == 'c') return NSVG_UNITS_PC; else if (units[0] == 'm' && units[1] == 'm') return NSVG_UNITS_MM; else if (units[0] == 'c' && units[1] == 'm') return NSVG_UNITS_CM; else if (units[0] == 'i' && units[1] == 'n') return NSVG_UNITS_IN; else if (units[0] == '%') return NSVG_UNITS_PERCENT; else if (units[0] == 'e' && units[1] == 'm') return NSVG_UNITS_EM; else if (units[0] == 'e' && units[1] == 'x') return NSVG_UNITS_EX; return NSVG_UNITS_USER; } static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) { NSVGcoordinate coord = {0, NSVG_UNITS_USER}; char units[32]=""; sscanf(str, "%f%s", &coord.value, units); coord.units = nsvg__parseUnits(units); return coord; } static NSVGcoordinate nsvg__coord(float v, int units) { NSVGcoordinate coord = {v, units}; return coord; } static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) { NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); return nsvg__convertToPixels(p, coord, orig, length); } static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) { const char* end; const char* ptr; char it[64]; *na = 0; ptr = str; while (*ptr && *ptr != '(') ++ptr; if (*ptr == 0) return 1; end = ptr; while (*end && *end != ')') ++end; if (*end == 0) return 1; while (ptr < end) { if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { if (*na >= maxNa) return 0; ptr = nsvg__parseNumber(ptr, it, 64); args[(*na)++] = (float)nsvg__atof(it); } else { ++ptr; } } return (int)(end - str); } static int nsvg__parseMatrix(float* xform, const char* str) { float t[6]; int na = 0; int len = nsvg__parseTransformArgs(str, t, 6, &na); if (na != 6) return len; memcpy(xform, t, sizeof(float)*6); return len; } static int nsvg__parseTranslate(float* xform, const char* str) { float args[2]; float t[6]; int na = 0; int len = nsvg__parseTransformArgs(str, args, 2, &na); if (na == 1) args[1] = 0.0; nsvg__xformSetTranslation(t, args[0], args[1]); memcpy(xform, t, sizeof(float)*6); return len; } static int nsvg__parseScale(float* xform, const char* str) { float args[2]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 2, &na); if (na == 1) args[1] = args[0]; nsvg__xformSetScale(t, args[0], args[1]); memcpy(xform, t, sizeof(float)*6); return len; } static int nsvg__parseSkewX(float* xform, const char* str) { float args[1]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 1, &na); nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); memcpy(xform, t, sizeof(float)*6); return len; } static int nsvg__parseSkewY(float* xform, const char* str) { float args[1]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 1, &na); nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); memcpy(xform, t, sizeof(float)*6); return len; } static int nsvg__parseRotate(float* xform, const char* str) { float args[3]; int na = 0; float m[6]; float t[6]; int len = nsvg__parseTransformArgs(str, args, 3, &na); if (na == 1) args[1] = args[2] = 0.0f; nsvg__xformIdentity(m); if (na > 1) { nsvg__xformSetTranslation(t, -args[1], -args[2]); nsvg__xformMultiply(m, t); } nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); nsvg__xformMultiply(m, t); if (na > 1) { nsvg__xformSetTranslation(t, args[1], args[2]); nsvg__xformMultiply(m, t); } memcpy(xform, m, sizeof(float)*6); return len; } static void nsvg__parseTransform(float* xform, const char* str) { float t[6]; nsvg__xformIdentity(xform); while (*str) { if (strncmp(str, "matrix", 6) == 0) str += nsvg__parseMatrix(t, str); else if (strncmp(str, "translate", 9) == 0) str += nsvg__parseTranslate(t, str); else if (strncmp(str, "scale", 5) == 0) str += nsvg__parseScale(t, str); else if (strncmp(str, "rotate", 6) == 0) str += nsvg__parseRotate(t, str); else if (strncmp(str, "skewX", 5) == 0) str += nsvg__parseSkewX(t, str); else if (strncmp(str, "skewY", 5) == 0) str += nsvg__parseSkewY(t, str); else{ ++str; continue; } nsvg__xformPremultiply(xform, t); } } static void nsvg__parseUrl(char* id, const char* str) { int i = 0; str += 4; // "url("; if (*str == '#') str++; while (i < 63 && *str != ')') { id[i] = *str++; i++; } id[i] = '\0'; } static char nsvg__parseLineCap(const char* str) { if (strcmp(str, "butt") == 0) return NSVG_CAP_BUTT; else if (strcmp(str, "round") == 0) return NSVG_CAP_ROUND; else if (strcmp(str, "square") == 0) return NSVG_CAP_SQUARE; // TODO: handle inherit. return NSVG_CAP_BUTT; } static char nsvg__parseLineJoin(const char* str) { if (strcmp(str, "miter") == 0) return NSVG_JOIN_MITER; else if (strcmp(str, "round") == 0) return NSVG_JOIN_ROUND; else if (strcmp(str, "bevel") == 0) return NSVG_JOIN_BEVEL; // TODO: handle inherit. return NSVG_JOIN_MITER; } static char nsvg__parseFillRule(const char* str) { if (strcmp(str, "nonzero") == 0) return NSVG_FILLRULE_NONZERO; else if (strcmp(str, "evenodd") == 0) return NSVG_FILLRULE_EVENODD; // TODO: handle inherit. return NSVG_FILLRULE_NONZERO; } static const char* nsvg__getNextDashItem(const char* s, char* it) { int n = 0; it[0] = '\0'; // Skip white spaces and commas while (*s && (nsvg__isspace(*s) || *s == ',')) s++; // Advance until whitespace, comma or end. while (*s && (!nsvg__isspace(*s) && *s != ',')) { if (n < 63) it[n++] = *s; s++; } it[n++] = '\0'; return s; } static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) { char item[64]; int count = 0, i; float sum = 0.0f; // Handle "none" if (str[0] == 'n') return 0; // Parse dashes while (*str) { str = nsvg__getNextDashItem(str, item); if (!*item) break; if (count < NSVG_MAX_DASHES) strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); } for (i = 0; i < count; i++) sum += strokeDashArray[i]; if (sum <= 1e-6f) count = 0; return count; } static void nsvg__parseStyle(NSVGparser* p, const char* str); static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) { float xform[6]; NSVGattrib* attr = nsvg__getAttr(p); if (!attr) return 0; if (strcmp(name, "style") == 0) { nsvg__parseStyle(p, value); } else if (strcmp(name, "display") == 0) { if (strcmp(value, "none") == 0) attr->visible &= ~NSVG_VIS_DISPLAY; // Don't reset ->visible on display:inline, one display:none hides the whole subtree } else if (strcmp(name, "visibility") == 0) { if (strcmp(value, "hidden") == 0) { attr->visible &= ~NSVG_VIS_VISIBLE; } else if (strcmp(value, "visible") == 0) { attr->visible |= NSVG_VIS_VISIBLE; } } else if (strcmp(name, "fill") == 0) { if (strcmp(value, "none") == 0) { attr->hasFill = 0; } else if (strncmp(value, "url(", 4) == 0) { attr->hasFill = 2; nsvg__parseUrl(attr->fillGradient, value); } else { attr->hasFill = 1; attr->fillColor = nsvg__parseColor(value); } } else if (strcmp(name, "opacity") == 0) { attr->opacity = nsvg__parseOpacity(value); } else if (strcmp(name, "fill-opacity") == 0) { attr->fillOpacity = nsvg__parseOpacity(value); } else if (strcmp(name, "stroke") == 0) { if (strcmp(value, "none") == 0) { attr->hasStroke = 0; } else if (strncmp(value, "url(", 4) == 0) { attr->hasStroke = 2; nsvg__parseUrl(attr->strokeGradient, value); } else { attr->hasStroke = 1; attr->strokeColor = nsvg__parseColor(value); } } else if (strcmp(name, "stroke-width") == 0) { attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); } else if (strcmp(name, "stroke-dasharray") == 0) { attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); } else if (strcmp(name, "stroke-dashoffset") == 0) { attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); } else if (strcmp(name, "stroke-opacity") == 0) { attr->strokeOpacity = nsvg__parseOpacity(value); } else if (strcmp(name, "stroke-linecap") == 0) { attr->strokeLineCap = nsvg__parseLineCap(value); } else if (strcmp(name, "stroke-linejoin") == 0) { attr->strokeLineJoin = nsvg__parseLineJoin(value); } else if (strcmp(name, "stroke-miterlimit") == 0) { attr->miterLimit = nsvg__parseMiterLimit(value); } else if (strcmp(name, "fill-rule") == 0) { attr->fillRule = nsvg__parseFillRule(value); } else if (strcmp(name, "font-size") == 0) { attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); } else if (strcmp(name, "transform") == 0) { nsvg__parseTransform(xform, value); nsvg__xformPremultiply(attr->xform, xform); } else if (strcmp(name, "stop-color") == 0) { attr->stopColor = nsvg__parseColor(value); } else if (strcmp(name, "stop-opacity") == 0) { attr->stopOpacity = nsvg__parseOpacity(value); } else if (strcmp(name, "offset") == 0) { attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); } else if (strcmp(name, "id") == 0) { strncpy(attr->id, value, 63); attr->id[63] = '\0'; } else if (strcmp(name, "class") == 0) { NSVGstyles* style = p->styles; while (style) { if (strcmp(style->name + 1, value) == 0) { break; } style = style->next; } if (style) { nsvg__parseStyle(p, style->description); } } else { return 0; } return 1; } static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) { const char* str; const char* val; char name[512]; char value[512]; int n; str = start; while (str < end && *str != ':') ++str; val = str; // Right Trim while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; ++str; n = (int)(str - start); if (n > 511) n = 511; if (n) memcpy(name, start, n); name[n] = 0; while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; n = (int)(end - val); if (n > 511) n = 511; if (n) memcpy(value, val, n); value[n] = 0; return nsvg__parseAttr(p, name, value); } static void nsvg__parseStyle(NSVGparser* p, const char* str) { const char* start; const char* end; while (*str) { // Left Trim while(*str && nsvg__isspace(*str)) ++str; start = str; while(*str && *str != ';') ++str; end = str; // Right Trim while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; ++end; nsvg__parseNameValue(p, start, end); if (*str) ++str; } } static void nsvg__parseAttribs(NSVGparser* p, const char** attr) { int i; for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "style") == 0) nsvg__parseStyle(p, attr[i + 1]); else nsvg__parseAttr(p, attr[i], attr[i + 1]); } } static int nsvg__getArgsPerElement(char cmd) { switch (cmd) { case 'v': case 'V': case 'h': case 'H': return 1; case 'm': case 'M': case 'l': case 'L': case 't': case 'T': return 2; case 'q': case 'Q': case 's': case 'S': return 4; case 'c': case 'C': return 6; case 'a': case 'A': return 7; } return 0; } static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) { if (rel) { *cpx += args[0]; *cpy += args[1]; } else { *cpx = args[0]; *cpy = args[1]; } nsvg__moveTo(p, *cpx, *cpy); } static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) { if (rel) { *cpx += args[0]; *cpy += args[1]; } else { *cpx = args[0]; *cpy = args[1]; } nsvg__lineTo(p, *cpx, *cpy); } static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) { if (rel) *cpx += args[0]; else *cpx = args[0]; nsvg__lineTo(p, *cpx, *cpy); } static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) { if (rel) *cpy += args[0]; else *cpy = args[0]; nsvg__lineTo(p, *cpx, *cpy); } static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, float* cpx2, float* cpy2, float* args, int rel) { float x2, y2, cx1, cy1, cx2, cy2; if (rel) { cx1 = *cpx + args[0]; cy1 = *cpy + args[1]; cx2 = *cpx + args[2]; cy2 = *cpy + args[3]; x2 = *cpx + args[4]; y2 = *cpy + args[5]; } else { cx1 = args[0]; cy1 = args[1]; cx2 = args[2]; cy2 = args[3]; x2 = args[4]; y2 = args[5]; } nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); *cpx2 = cx2; *cpy2 = cy2; *cpx = x2; *cpy = y2; } static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, float* cpx2, float* cpy2, float* args, int rel) { float x1, y1, x2, y2, cx1, cy1, cx2, cy2; x1 = *cpx; y1 = *cpy; if (rel) { cx2 = *cpx + args[0]; cy2 = *cpy + args[1]; x2 = *cpx + args[2]; y2 = *cpy + args[3]; } else { cx2 = args[0]; cy2 = args[1]; x2 = args[2]; y2 = args[3]; } cx1 = 2*x1 - *cpx2; cy1 = 2*y1 - *cpy2; nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); *cpx2 = cx2; *cpy2 = cy2; *cpx = x2; *cpy = y2; } static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, float* cpx2, float* cpy2, float* args, int rel) { float x1, y1, x2, y2, cx, cy; float cx1, cy1, cx2, cy2; x1 = *cpx; y1 = *cpy; if (rel) { cx = *cpx + args[0]; cy = *cpy + args[1]; x2 = *cpx + args[2]; y2 = *cpy + args[3]; } else { cx = args[0]; cy = args[1]; x2 = args[2]; y2 = args[3]; } // Convert to cubic bezier cx1 = x1 + 2.0f/3.0f*(cx - x1); cy1 = y1 + 2.0f/3.0f*(cy - y1); cx2 = x2 + 2.0f/3.0f*(cx - x2); cy2 = y2 + 2.0f/3.0f*(cy - y2); nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); *cpx2 = cx; *cpy2 = cy; *cpx = x2; *cpy = y2; } static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, float* cpx2, float* cpy2, float* args, int rel) { float x1, y1, x2, y2, cx, cy; float cx1, cy1, cx2, cy2; x1 = *cpx; y1 = *cpy; if (rel) { x2 = *cpx + args[0]; y2 = *cpy + args[1]; } else { x2 = args[0]; y2 = args[1]; } cx = 2*x1 - *cpx2; cy = 2*y1 - *cpy2; // Convert to cubix bezier cx1 = x1 + 2.0f/3.0f*(cx - x1); cy1 = y1 + 2.0f/3.0f*(cy - y1); cx2 = x2 + 2.0f/3.0f*(cx - x2); cy2 = y2 + 2.0f/3.0f*(cy - y2); nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); *cpx2 = cx; *cpy2 = cy; *cpx = x2; *cpy = y2; } static float nsvg__sqr(float x) { return x*x; } static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } static float nsvg__vecrat(float ux, float uy, float vx, float vy) { return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); } static float nsvg__vecang(float ux, float uy, float vx, float vy) { float r = nsvg__vecrat(ux,uy, vx,vy); if (r < -1.0f) r = -1.0f; if (r > 1.0f) r = 1.0f; return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); } static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) { // Ported from canvg (https://code.google.com/p/canvg/) float rx, ry, rotx; float x1, y1, x2, y2, cx, cy, dx, dy, d; float x1p, y1p, cxp, cyp, s, sa, sb; float ux, uy, vx, vy, a1, da; float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; float sinrx, cosrx; int fa, fs; int i, ndivs; float hda, kappa; rx = fabsf(args[0]); // y radius ry = fabsf(args[1]); // x radius rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction x1 = *cpx; // start point y1 = *cpy; if (rel) { // end point x2 = *cpx + args[5]; y2 = *cpy + args[6]; } else { x2 = args[5]; y2 = args[6]; } dx = x1 - x2; dy = y1 - y2; d = sqrtf(dx*dx + dy*dy); if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { // The arc degenerates to a line nsvg__lineTo(p, x2, y2); *cpx = x2; *cpy = y2; return; } sinrx = sinf(rotx); cosrx = cosf(rotx); // Convert to center point parameterization. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes // 1) Compute x1', y1' x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); if (d > 1) { d = sqrtf(d); rx *= d; ry *= d; } // 2) Compute cx', cy' s = 0.0f; sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); if (sa < 0.0f) sa = 0.0f; if (sb > 0.0f) s = sqrtf(sa / sb); if (fa == fs) s = -s; cxp = s * rx * y1p / ry; cyp = s * -ry * x1p / rx; // 3) Compute cx,cy from cx',cy' cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; // 4) Calculate theta1, and delta theta. ux = (x1p - cxp) / rx; uy = (y1p - cyp) / ry; vx = (-x1p - cxp) / rx; vy = (-y1p - cyp) / ry; a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle da = nsvg__vecang(ux,uy, vx,vy); // Delta angle // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; if (fs == 0 && da > 0) da -= 2 * NSVG_PI; else if (fs == 1 && da < 0) da += 2 * NSVG_PI; // Approximate the arc using cubic spline segments. t[0] = cosrx; t[1] = sinrx; t[2] = -sinrx; t[3] = cosrx; t[4] = cx; t[5] = cy; // Split arc into max 90 degree segments. // The loop assumes an iteration per end point (including start and end), this +1. ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); hda = (da / (float)ndivs) / 2.0f; kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); if (da < 0.0f) kappa = -kappa; for (i = 0; i <= ndivs; i++) { a = a1 + da * ((float)i/(float)ndivs); dx = cosf(a); dy = sinf(a); nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent if (i > 0) nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); px = x; py = y; ptanx = tanx; ptany = tany; } *cpx = x2; *cpy = y2; } static void nsvg__parsePath(NSVGparser* p, const char** attr) { const char* s = NULL; char cmd = '\0'; float args[10]; int nargs; int rargs = 0; float cpx, cpy, cpx2, cpy2; const char* tmp[4]; char closedFlag; int i; char item[64]; for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "d") == 0) { s = attr[i + 1]; } else { tmp[0] = attr[i]; tmp[1] = attr[i + 1]; tmp[2] = 0; tmp[3] = 0; nsvg__parseAttribs(p, tmp); } } if (s) { nsvg__resetPath(p); cpx = 0; cpy = 0; cpx2 = 0; cpy2 = 0; closedFlag = 0; nargs = 0; while (*s) { s = nsvg__getNextPathItem(s, item); if (!*item) break; if (nsvg__isnum(item[0])) { if (nargs < 10) args[nargs++] = (float)nsvg__atof(item); if (nargs >= rargs) { switch (cmd) { case 'm': case 'M': nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); // Moveto can be followed by multiple coordinate pairs, // which should be treated as linetos. cmd = (cmd == 'm') ? 'l' : 'L'; rargs = nsvg__getArgsPerElement(cmd); cpx2 = cpx; cpy2 = cpy; break; case 'l': case 'L': nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); cpx2 = cpx; cpy2 = cpy; break; case 'H': case 'h': nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); cpx2 = cpx; cpy2 = cpy; break; case 'V': case 'v': nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); cpx2 = cpx; cpy2 = cpy; break; case 'C': case 'c': nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); break; case 'S': case 's': nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); break; case 'Q': case 'q': nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); break; case 'T': case 't': nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); break; case 'A': case 'a': nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); cpx2 = cpx; cpy2 = cpy; break; default: if (nargs >= 2) { cpx = args[nargs-2]; cpy = args[nargs-1]; cpx2 = cpx; cpy2 = cpy; } break; } nargs = 0; } } else { cmd = item[0]; rargs = nsvg__getArgsPerElement(cmd); if (cmd == 'M' || cmd == 'm') { // Commit path. if (p->npts > 0) nsvg__addPath(p, closedFlag); // Start new subpath. nsvg__resetPath(p); closedFlag = 0; nargs = 0; } else if (cmd == 'Z' || cmd == 'z') { closedFlag = 1; // Commit path. if (p->npts > 0) { // Move current point to first point cpx = p->pts[0]; cpy = p->pts[1]; cpx2 = cpx; cpy2 = cpy; nsvg__addPath(p, closedFlag); } // Start new subpath. nsvg__resetPath(p); nsvg__moveTo(p, cpx, cpy); closedFlag = 0; nargs = 0; } } } // Commit path. if (p->npts) nsvg__addPath(p, closedFlag); } nsvg__addShape(p); } static void nsvg__parseRect(NSVGparser* p, const char** attr) { float x = 0.0f; float y = 0.0f; float w = 0.0f; float h = 0.0f; float rx = -1.0f; // marks not set float ry = -1.0f; int i; for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); } } if (rx < 0.0f && ry > 0.0f) rx = ry; if (ry < 0.0f && rx > 0.0f) ry = rx; if (rx < 0.0f) rx = 0.0f; if (ry < 0.0f) ry = 0.0f; if (rx > w/2.0f) rx = w/2.0f; if (ry > h/2.0f) ry = h/2.0f; if (w != 0.0f && h != 0.0f) { nsvg__resetPath(p); if (rx < 0.00001f || ry < 0.0001f) { nsvg__moveTo(p, x, y); nsvg__lineTo(p, x+w, y); nsvg__lineTo(p, x+w, y+h); nsvg__lineTo(p, x, y+h); } else { // Rounded rectangle nsvg__moveTo(p, x+rx, y); nsvg__lineTo(p, x+w-rx, y); nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); nsvg__lineTo(p, x+w, y+h-ry); nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); nsvg__lineTo(p, x+rx, y+h); nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); nsvg__lineTo(p, x, y+ry); nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); } nsvg__addPath(p, 1); nsvg__addShape(p); } } static void nsvg__parseCircle(NSVGparser* p, const char** attr) { float cx = 0.0f; float cy = 0.0f; float r = 0.0f; int i; for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); } } if (r > 0.0f) { nsvg__resetPath(p); nsvg__moveTo(p, cx+r, cy); nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); nsvg__addPath(p, 1); nsvg__addShape(p); } } static void nsvg__parseEllipse(NSVGparser* p, const char** attr) { float cx = 0.0f; float cy = 0.0f; float rx = 0.0f; float ry = 0.0f; int i; for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); } } if (rx > 0.0f && ry > 0.0f) { nsvg__resetPath(p); nsvg__moveTo(p, cx+rx, cy); nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); nsvg__addPath(p, 1); nsvg__addShape(p); } } static void nsvg__parseLine(NSVGparser* p, const char** attr) { float x1 = 0.0; float y1 = 0.0; float x2 = 0.0; float y2 = 0.0; int i; for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); } } nsvg__resetPath(p); nsvg__moveTo(p, x1, y1); nsvg__lineTo(p, x2, y2); nsvg__addPath(p, 0); nsvg__addShape(p); } static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) { int i; const char* s; float args[2]; int nargs, npts = 0; char item[64]; nsvg__resetPath(p); for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "points") == 0) { s = attr[i + 1]; nargs = 0; while (*s) { s = nsvg__getNextPathItem(s, item); args[nargs++] = (float)nsvg__atof(item); if (nargs >= 2) { if (npts == 0) nsvg__moveTo(p, args[0], args[1]); else nsvg__lineTo(p, args[0], args[1]); nargs = 0; npts++; } } } } } nsvg__addPath(p, (char)closeFlag); nsvg__addShape(p); } static void nsvg__parseSVG(NSVGparser* p, const char** attr) { int i; for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "width") == 0) { p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); } else if (strcmp(attr[i], "height") == 0) { p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); } else if (strcmp(attr[i], "viewBox") == 0) { sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight); } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { if (strstr(attr[i + 1], "none") != 0) { // No uniform scaling p->alignType = NSVG_ALIGN_NONE; } else { // Parse X align if (strstr(attr[i + 1], "xMin") != 0) p->alignX = NSVG_ALIGN_MIN; else if (strstr(attr[i + 1], "xMid") != 0) p->alignX = NSVG_ALIGN_MID; else if (strstr(attr[i + 1], "xMax") != 0) p->alignX = NSVG_ALIGN_MAX; // Parse X align if (strstr(attr[i + 1], "yMin") != 0) p->alignY = NSVG_ALIGN_MIN; else if (strstr(attr[i + 1], "yMid") != 0) p->alignY = NSVG_ALIGN_MID; else if (strstr(attr[i + 1], "yMax") != 0) p->alignY = NSVG_ALIGN_MAX; // Parse meet/slice p->alignType = NSVG_ALIGN_MEET; if (strstr(attr[i + 1], "slice") != 0) p->alignType = NSVG_ALIGN_SLICE; } } } } } static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) { int i; NSVGgradientData* grad = (NSVGgradientData*)NANOSVG_malloc(sizeof(NSVGgradientData)); if (grad == NULL) return; memset(grad, 0, sizeof(NSVGgradientData)); grad->units = NSVG_OBJECT_SPACE; grad->type = type; if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); } nsvg__xformIdentity(grad->xform); for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "id") == 0) { strncpy(grad->id, attr[i+1], 63); grad->id[63] = '\0'; } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "gradientUnits") == 0) { if (strcmp(attr[i+1], "objectBoundingBox") == 0) grad->units = NSVG_OBJECT_SPACE; else grad->units = NSVG_USER_SPACE; } else if (strcmp(attr[i], "gradientTransform") == 0) { nsvg__parseTransform(grad->xform, attr[i + 1]); } else if (strcmp(attr[i], "cx") == 0) { grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "cy") == 0) { grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "r") == 0) { grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "fx") == 0) { grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "fy") == 0) { grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "x1") == 0) { grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "y1") == 0) { grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "x2") == 0) { grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "y2") == 0) { grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "spreadMethod") == 0) { if (strcmp(attr[i+1], "pad") == 0) grad->spread = NSVG_SPREAD_PAD; else if (strcmp(attr[i+1], "reflect") == 0) grad->spread = NSVG_SPREAD_REFLECT; else if (strcmp(attr[i+1], "repeat") == 0) grad->spread = NSVG_SPREAD_REPEAT; } else if (strcmp(attr[i], "xlink:href") == 0) { const char *href = attr[i+1]; strncpy(grad->ref, href+1, 62); grad->ref[62] = '\0'; } } } grad->next = p->gradients; p->gradients = grad; } static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) { NSVGattrib* curAttr = nsvg__getAttr(p); NSVGgradientData* grad; NSVGgradientStop* stop; int i, idx; curAttr->stopOffset = 0; curAttr->stopColor = 0; curAttr->stopOpacity = 1.0f; for (i = 0; attr[i]; i += 2) { nsvg__parseAttr(p, attr[i], attr[i + 1]); } // Add stop to the last gradient. grad = p->gradients; if (grad == NULL) return; grad->nstops++; grad->stops = (NSVGgradientStop*)NANOSVG_realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); if (grad->stops == NULL) return; // Insert idx = grad->nstops-1; for (i = 0; i < grad->nstops-1; i++) { if (curAttr->stopOffset < grad->stops[i].offset) { idx = i; break; } } if (idx != grad->nstops-1) { for (i = grad->nstops-1; i > idx; i--) grad->stops[i] = grad->stops[i-1]; } stop = &grad->stops[idx]; stop->color = curAttr->stopColor; stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; stop->offset = curAttr->stopOffset; } static void nsvg__startElement(void* ud, const char* el, const char** attr) { NSVGparser* p = (NSVGparser*)ud; if (p->defsFlag) { // Skip everything but gradients in defs if (strcmp(el, "linearGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); } else if (strcmp(el, "radialGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); } else if (strcmp(el, "stop") == 0) { nsvg__parseGradientStop(p, attr); } return; } if (strcmp(el, "g") == 0) { nsvg__pushAttr(p); nsvg__parseAttribs(p, attr); } else if (strcmp(el, "path") == 0) { if (p->pathFlag) // Do not allow nested paths. return; nsvg__pushAttr(p); nsvg__parsePath(p, attr); nsvg__popAttr(p); } else if (strcmp(el, "rect") == 0) { nsvg__pushAttr(p); nsvg__parseRect(p, attr); nsvg__popAttr(p); } else if (strcmp(el, "circle") == 0) { nsvg__pushAttr(p); nsvg__parseCircle(p, attr); nsvg__popAttr(p); } else if (strcmp(el, "ellipse") == 0) { nsvg__pushAttr(p); nsvg__parseEllipse(p, attr); nsvg__popAttr(p); } else if (strcmp(el, "line") == 0) { nsvg__pushAttr(p); nsvg__parseLine(p, attr); nsvg__popAttr(p); } else if (strcmp(el, "polyline") == 0) { nsvg__pushAttr(p); nsvg__parsePoly(p, attr, 0); nsvg__popAttr(p); } else if (strcmp(el, "polygon") == 0) { nsvg__pushAttr(p); nsvg__parsePoly(p, attr, 1); nsvg__popAttr(p); } else if (strcmp(el, "linearGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); } else if (strcmp(el, "radialGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); } else if (strcmp(el, "stop") == 0) { nsvg__parseGradientStop(p, attr); } else if (strcmp(el, "defs") == 0) { p->defsFlag = 1; } else if (strcmp(el, "svg") == 0) { nsvg__parseSVG(p, attr); } else if (strcmp(el, "style") == 0) { p->styleFlag = 1; } } static void nsvg__endElement(void* ud, const char* el) { NSVGparser* p = (NSVGparser*)ud; if (strcmp(el, "g") == 0) { nsvg__popAttr(p); } else if (strcmp(el, "path") == 0) { p->pathFlag = 0; } else if (strcmp(el, "defs") == 0) { p->defsFlag = 0; } else if (strcmp(el, "style") == 0) { p->styleFlag = 0; } } static char *nsvg__strndup(const char *s, size_t n) { char *result; size_t len = strlen(s); if (n < len) len = n; result = (char*)NANOSVG_malloc(len+1); if (!result) return 0; result[len] = '\0'; return (char *)memcpy(result, s, len); } static void nsvg__content(void* ud, const char* s) { NSVGparser* p = (NSVGparser*)ud; if (p->styleFlag) { int state = 0; const char* start = NULL; while (*s) { char c = *s; if (nsvg__isspace(c) || c == '{') { if (state == 1) { NSVGstyles* next = p->styles; p->styles = (NSVGstyles*)malloc(sizeof(NSVGstyles)); p->styles->next = next; p->styles->name = nsvg__strndup(start, (size_t)(s - start)); start = s + 1; state = 2; } } else if (state == 2 && c == '}') { p->styles->description = nsvg__strndup(start, (size_t)(s - start)); state = 0; } else if (state == 0) { start = s; state = 1; } s++; /* if (*s == '{' && state == NSVG_XML_CONTENT) { // Start of a tag *s++ = '\0'; nsvg__parseContent(mark, contentCb, ud); mark = s; state = NSVG_XML_TAG; } else if (*s == '>' && state == NSVG_XML_TAG) { // Start of a content or new tag. *s++ = '\0'; nsvg__parseElement(mark, startelCb, endelCb, ud); mark = s; state = NSVG_XML_CONTENT; } else { s++; } */ } } } static void nsvg__imageBounds(NSVGparser* p, float* bounds) { NSVGshape* shape; shape = p->image->shapes; if (shape == NULL) { bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; return; } bounds[0] = shape->bounds[0]; bounds[1] = shape->bounds[1]; bounds[2] = shape->bounds[2]; bounds[3] = shape->bounds[3]; for (shape = shape->next; shape != NULL; shape = shape->next) { bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); } } static float nsvg__viewAlign(float content, float container, int type) { if (type == NSVG_ALIGN_MIN) return 0; else if (type == NSVG_ALIGN_MAX) return container - content; // mid return (container - content) * 0.5f; } static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) { float t[6]; nsvg__xformSetTranslation(t, tx, ty); nsvg__xformMultiply (grad->xform, t); nsvg__xformSetScale(t, sx, sy); nsvg__xformMultiply (grad->xform, t); } static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) { NSVGshape* shape; NSVGpath* path; float tx, ty, sx, sy, us, bounds[4], t[6], avgs; int i; float* pt; // Guess image size if not set completely. nsvg__imageBounds(p, bounds); if (p->viewWidth == 0) { if (p->image->width > 0) { p->viewWidth = p->image->width; } else { p->viewMinx = bounds[0]; p->viewWidth = bounds[2] - bounds[0]; } } if (p->viewHeight == 0) { if (p->image->height > 0) { p->viewHeight = p->image->height; } else { p->viewMiny = bounds[1]; p->viewHeight = bounds[3] - bounds[1]; } } if (p->image->width == 0) p->image->width = p->viewWidth; if (p->image->height == 0) p->image->height = p->viewHeight; tx = -p->viewMinx; ty = -p->viewMiny; sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; // Unit scaling us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); // Fix aspect ratio if (p->alignType == NSVG_ALIGN_MEET) { // fit whole image into viewbox sx = sy = nsvg__minf(sx, sy); tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; } else if (p->alignType == NSVG_ALIGN_SLICE) { // fill whole viewbox with image sx = sy = nsvg__maxf(sx, sy); tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; } // Transform sx *= us; sy *= us; avgs = (sx+sy) / 2.0f; for (shape = p->image->shapes; shape != NULL; shape = shape->next) { shape->bounds[0] = (shape->bounds[0] + tx) * sx; shape->bounds[1] = (shape->bounds[1] + ty) * sy; shape->bounds[2] = (shape->bounds[2] + tx) * sx; shape->bounds[3] = (shape->bounds[3] + ty) * sy; for (path = shape->paths; path != NULL; path = path->next) { path->bounds[0] = (path->bounds[0] + tx) * sx; path->bounds[1] = (path->bounds[1] + ty) * sy; path->bounds[2] = (path->bounds[2] + tx) * sx; path->bounds[3] = (path->bounds[3] + ty) * sy; for (i =0; i < path->npts; i++) { pt = &path->pts[i*2]; pt[0] = (pt[0] + tx) * sx; pt[1] = (pt[1] + ty) * sy; } } if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); nsvg__xformInverse(shape->fill.gradient->xform, t); } if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); nsvg__xformInverse(shape->stroke.gradient->xform, t); } shape->strokeWidth *= avgs; shape->strokeDashOffset *= avgs; for (i = 0; i < shape->strokeDashCount; i++) shape->strokeDashArray[i] *= avgs; } } NANOSVG_SCOPE NSVGimage* nsvgParse(char* input, const char* units, float dpi) { NSVGparser* p; NSVGimage* ret = 0; p = nsvg__createParser(); if (p == NULL) { return NULL; } p->dpi = dpi; nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); // Scale to viewBox nsvg__scaleToViewbox(p, units); ret = p->image; p->image = NULL; nsvg__deleteParser(p); return ret; } NANOSVG_SCOPE NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) { FILE* fp = NULL; size_t size; char* data = NULL; NSVGimage* image = NULL; fp = fopen(filename, "rb"); if (!fp) goto error; fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); data = (char*)NANOSVG_malloc(size+1); if (data == NULL) goto error; if (fread(data, 1, size, fp) != size) goto error; data[size] = '\0'; // Must be null terminated. fclose(fp); image = nsvgParse(data, units, dpi); NANOSVG_free(data); return image; error: if (fp) fclose(fp); if (data) NANOSVG_free(data); if (image) nsvgDelete(image); return NULL; } NANOSVG_SCOPE void nsvgDelete(NSVGimage* image) { NSVGshape *snext, *shape; if (image == NULL) return; shape = image->shapes; while (shape != NULL) { snext = shape->next; nsvg__deletePaths(shape->paths); nsvg__deletePaint(&shape->fill); nsvg__deletePaint(&shape->stroke); NANOSVG_free(shape); shape = snext; } NANOSVG_free(image); } #endif |
Added generic/nanosvgrast.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 | /* * Copyright (c) 2013-14 Mikko Mononen [email protected] * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * The polygon rasterization is heavily based on stb_truetype rasterizer * by Sean Barrett - http://nothings.org/ * */ #ifndef NANOSVGRAST_H #define NANOSVGRAST_H #ifdef __cplusplus extern "C" { #endif #ifndef NANOSVG_SCOPE #define NANOSVG_SCOPE #endif #ifndef NANOSVG_malloc #define NANOSVG_malloc malloc #endif #ifndef NANOSVG_realloc #define NANOSVG_realloc realloc #endif #ifndef NANOSVG_free #define NANOSVG_free free #endif typedef struct NSVGrasterizer NSVGrasterizer; /* Example Usage: // Load SVG struct SNVGImage* image = nsvgParseFromFile("test.svg."); // Create rasterizer (can be used to render multiple images). struct NSVGrasterizer* rast = nsvgCreateRasterizer(); // Allocate memory for image unsigned char* img = malloc(w*h*4); // Rasterize nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); */ // Allocated rasterizer context. NANOSVG_SCOPE NSVGrasterizer* nsvgCreateRasterizer(); // Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) // r - pointer to rasterizer context // image - pointer to image to rasterize // tx,ty - image offset (applied after scaling) // scale - image scale // dst - pointer to destination image data, 4 bytes per pixel (RGBA) // w - width of the image to render // h - height of the image to render // stride - number of bytes per scaleline in the destination buffer NANOSVG_SCOPE void nsvgRasterize(NSVGrasterizer* r, NSVGimage* image, float tx, float ty, float scale, unsigned char* dst, int w, int h, int stride); // Deletes rasterizer context. NANOSVG_SCOPE void nsvgDeleteRasterizer(NSVGrasterizer*); #ifdef __cplusplus } #endif #endif // NANOSVGRAST_H #ifdef NANOSVGRAST_IMPLEMENTATION #include <math.h> #define NSVG__SUBSAMPLES 5 #define NSVG__FIXSHIFT 10 #define NSVG__FIX (1 << NSVG__FIXSHIFT) #define NSVG__FIXMASK (NSVG__FIX-1) #define NSVG__MEMPAGE_SIZE 1024 typedef struct NSVGedge { float x0,y0, x1,y1; int dir; struct NSVGedge* next; } NSVGedge; typedef struct NSVGpoint { float x, y; float dx, dy; float len; float dmx, dmy; unsigned char flags; } NSVGpoint; typedef struct NSVGactiveEdge { int x,dx; float ey; int dir; struct NSVGactiveEdge *next; } NSVGactiveEdge; typedef struct NSVGmemPage { unsigned char mem[NSVG__MEMPAGE_SIZE]; int size; struct NSVGmemPage* next; } NSVGmemPage; typedef struct NSVGcachedPaint { char type; char spread; float xform[6]; unsigned int colors[256]; } NSVGcachedPaint; struct NSVGrasterizer { float px, py; float tessTol; float distTol; NSVGedge* edges; int nedges; int cedges; NSVGpoint* points; int npoints; int cpoints; NSVGpoint* points2; int npoints2; int cpoints2; NSVGactiveEdge* freelist; NSVGmemPage* pages; NSVGmemPage* curpage; unsigned char* scanline; int cscanline; unsigned char* bitmap; int width, height, stride; }; NANOSVG_SCOPE NSVGrasterizer* nsvgCreateRasterizer() { NSVGrasterizer* r = (NSVGrasterizer*)NANOSVG_malloc(sizeof(NSVGrasterizer)); if (r == NULL) goto error; memset(r, 0, sizeof(NSVGrasterizer)); r->tessTol = 0.25f; r->distTol = 0.01f; return r; error: nsvgDeleteRasterizer(r); return NULL; } NANOSVG_SCOPE void nsvgDeleteRasterizer(NSVGrasterizer* r) { NSVGmemPage* p; if (r == NULL) return; p = r->pages; while (p != NULL) { NSVGmemPage* next = p->next; NANOSVG_free(p); p = next; } if (r->edges) NANOSVG_free(r->edges); if (r->points) NANOSVG_free(r->points); if (r->points2) NANOSVG_free(r->points2); if (r->scanline) NANOSVG_free(r->scanline); NANOSVG_free(r); } static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) { NSVGmemPage *newp; // If using existing chain, return the next page in chain if (cur != NULL && cur->next != NULL) { return cur->next; } // Alloc new page newp = (NSVGmemPage*)NANOSVG_malloc(sizeof(NSVGmemPage)); if (newp == NULL) return NULL; memset(newp, 0, sizeof(NSVGmemPage)); // Add to linked list if (cur != NULL) cur->next = newp; else r->pages = newp; return newp; } static void nsvg__resetPool(NSVGrasterizer* r) { NSVGmemPage* p = r->pages; while (p != NULL) { p->size = 0; p = p->next; } r->curpage = r->pages; } static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) { unsigned char* buf; if (size > NSVG__MEMPAGE_SIZE) return NULL; if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { r->curpage = nsvg__nextPage(r, r->curpage); } buf = &r->curpage->mem[r->curpage->size]; r->curpage->size += size; return buf; } static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) { float dx = x2 - x1; float dy = y2 - y1; return dx*dx + dy*dy < tol*tol; } static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) { NSVGpoint* pt; if (r->npoints > 0) { pt = &r->points[r->npoints-1]; if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { pt->flags = (unsigned char)(pt->flags | flags); return; } } if (r->npoints+1 > r->cpoints) { r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; r->points = (NSVGpoint*)NANOSVG_realloc(r->points, sizeof(NSVGpoint) * r->cpoints); if (r->points == NULL) return; } pt = &r->points[r->npoints]; pt->x = x; pt->y = y; pt->flags = (unsigned char)flags; r->npoints++; } static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) { if (r->npoints+1 > r->cpoints) { r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; r->points = (NSVGpoint*)NANOSVG_realloc(r->points, sizeof(NSVGpoint) * r->cpoints); if (r->points == NULL) return; } r->points[r->npoints] = pt; r->npoints++; } static void nsvg__duplicatePoints(NSVGrasterizer* r) { if (r->npoints > r->cpoints2) { r->cpoints2 = r->npoints; r->points2 = (NSVGpoint*)NANOSVG_realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); if (r->points2 == NULL) return; } memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); r->npoints2 = r->npoints; } static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) { NSVGedge* e; // Skip horizontal edges if (y0 == y1) return; if (r->nedges+1 > r->cedges) { r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; r->edges = (NSVGedge*)NANOSVG_realloc(r->edges, sizeof(NSVGedge) * r->cedges); if (r->edges == NULL) return; } e = &r->edges[r->nedges]; r->nedges++; if (y0 < y1) { e->x0 = x0; e->y0 = y0; e->x1 = x1; e->y1 = y1; e->dir = 1; } else { e->x0 = x1; e->y0 = y1; e->x1 = x0; e->y1 = y0; e->dir = -1; } } static float nsvg__normalize(float *x, float* y) { float d = sqrtf((*x)*(*x) + (*y)*(*y)); if (d > 1e-6f) { float id = 1.0f / d; *x *= id; *y *= id; } return d; } static float nsvg__absf(float x) { return x < 0 ? -x : x; } static void nsvg__flattenCubicBez(NSVGrasterizer* r, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int level, int type) { float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; float dx,dy,d2,d3; if (level > 10) return; x12 = (x1+x2)*0.5f; y12 = (y1+y2)*0.5f; x23 = (x2+x3)*0.5f; y23 = (y2+y3)*0.5f; x34 = (x3+x4)*0.5f; y34 = (y3+y4)*0.5f; x123 = (x12+x23)*0.5f; y123 = (y12+y23)*0.5f; dx = x4 - x1; dy = y4 - y1; d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { nsvg__addPathPoint(r, x4, y4, type); return; } x234 = (x23+x34)*0.5f; y234 = (y23+y34)*0.5f; x1234 = (x123+x234)*0.5f; y1234 = (y123+y234)*0.5f; nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); } static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) { int i, j; NSVGpath* path; for (path = shape->paths; path != NULL; path = path->next) { r->npoints = 0; // Flatten path nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); for (i = 0; i < path->npts-1; i += 3) { float* p = &path->pts[i*2]; nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); } // Close path nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); // Build edges for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); } } enum NSVGpointFlags { NSVG_PT_CORNER = 0x01, NSVG_PT_BEVEL = 0x02, NSVG_PT_LEFT = 0x04 }; static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) { float w = lineWidth * 0.5f; float dx = p1->x - p0->x; float dy = p1->y - p0->y; float len = nsvg__normalize(&dx, &dy); float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; float dlx = dy, dly = -dx; float lx = px - dlx*w, ly = py - dly*w; float rx = px + dlx*w, ry = py + dly*w; left->x = lx; left->y = ly; right->x = rx; right->y = ry; } static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) { float w = lineWidth * 0.5f; float px = p->x, py = p->y; float dlx = dy, dly = -dx; float lx = px - dlx*w, ly = py - dly*w; float rx = px + dlx*w, ry = py + dly*w; nsvg__addEdge(r, lx, ly, rx, ry); if (connect) { nsvg__addEdge(r, left->x, left->y, lx, ly); nsvg__addEdge(r, rx, ry, right->x, right->y); } left->x = lx; left->y = ly; right->x = rx; right->y = ry; } static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) { float w = lineWidth * 0.5f; float px = p->x - dx*w, py = p->y - dy*w; float dlx = dy, dly = -dx; float lx = px - dlx*w, ly = py - dly*w; float rx = px + dlx*w, ry = py + dly*w; nsvg__addEdge(r, lx, ly, rx, ry); if (connect) { nsvg__addEdge(r, left->x, left->y, lx, ly); nsvg__addEdge(r, rx, ry, right->x, right->y); } left->x = lx; left->y = ly; right->x = rx; right->y = ry; } #ifndef NSVG_PI #define NSVG_PI (3.14159265358979323846264338327f) #endif static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) { int i; float w = lineWidth * 0.5f; float px = p->x, py = p->y; float dlx = dy, dly = -dx; float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; for (i = 0; i < ncap; i++) { float a = (float)i/(float)(ncap-1)*NSVG_PI; float ax = cosf(a) * w, ay = sinf(a) * w; float x = px - dlx*ax - dx*ay; float y = py - dly*ax - dy*ay; if (i > 0) nsvg__addEdge(r, prevx, prevy, x, y); prevx = x; prevy = y; if (i == 0) { lx = x; ly = y; } else if (i == ncap-1) { rx = x; ry = y; } } if (connect) { nsvg__addEdge(r, left->x, left->y, lx, ly); nsvg__addEdge(r, rx, ry, right->x, right->y); } left->x = lx; left->y = ly; right->x = rx; right->y = ry; } static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) { float w = lineWidth * 0.5f; float dlx0 = p0->dy, dly0 = -p0->dx; float dlx1 = p1->dy, dly1 = -p1->dx; float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); nsvg__addEdge(r, lx0, ly0, left->x, left->y); nsvg__addEdge(r, lx1, ly1, lx0, ly0); nsvg__addEdge(r, right->x, right->y, rx0, ry0); nsvg__addEdge(r, rx0, ry0, rx1, ry1); left->x = lx1; left->y = ly1; right->x = rx1; right->y = ry1; } static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) { float w = lineWidth * 0.5f; float dlx0 = p0->dy, dly0 = -p0->dx; float dlx1 = p1->dy, dly1 = -p1->dx; float lx0, rx0, lx1, rx1; float ly0, ry0, ly1, ry1; if (p1->flags & NSVG_PT_LEFT) { lx0 = lx1 = p1->x - p1->dmx * w; ly0 = ly1 = p1->y - p1->dmy * w; nsvg__addEdge(r, lx1, ly1, left->x, left->y); rx0 = p1->x + (dlx0 * w); ry0 = p1->y + (dly0 * w); rx1 = p1->x + (dlx1 * w); ry1 = p1->y + (dly1 * w); nsvg__addEdge(r, right->x, right->y, rx0, ry0); nsvg__addEdge(r, rx0, ry0, rx1, ry1); } else { lx0 = p1->x - (dlx0 * w); ly0 = p1->y - (dly0 * w); lx1 = p1->x - (dlx1 * w); ly1 = p1->y - (dly1 * w); nsvg__addEdge(r, lx0, ly0, left->x, left->y); nsvg__addEdge(r, lx1, ly1, lx0, ly0); rx0 = rx1 = p1->x + p1->dmx * w; ry0 = ry1 = p1->y + p1->dmy * w; nsvg__addEdge(r, right->x, right->y, rx1, ry1); } left->x = lx1; left->y = ly1; right->x = rx1; right->y = ry1; } static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) { int i, n; float w = lineWidth * 0.5f; float dlx0 = p0->dy, dly0 = -p0->dx; float dlx1 = p1->dy, dly1 = -p1->dx; float a0 = atan2f(dly0, dlx0); float a1 = atan2f(dly1, dlx1); float da = a1 - a0; float lx, ly, rx, ry; if (da < NSVG_PI) da += NSVG_PI*2; if (da > NSVG_PI) da -= NSVG_PI*2; n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); if (n < 2) n = 2; if (n > ncap) n = ncap; lx = left->x; ly = left->y; rx = right->x; ry = right->y; for (i = 0; i < n; i++) { float u = (float)i/(float)(n-1); float a = a0 + u*da; float ax = cosf(a) * w, ay = sinf(a) * w; float lx1 = p1->x - ax, ly1 = p1->y - ay; float rx1 = p1->x + ax, ry1 = p1->y + ay; nsvg__addEdge(r, lx1, ly1, lx, ly); nsvg__addEdge(r, rx, ry, rx1, ry1); lx = lx1; ly = ly1; rx = rx1; ry = ry1; } left->x = lx; left->y = ly; right->x = rx; right->y = ry; } static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) { float w = lineWidth * 0.5f; float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); nsvg__addEdge(r, lx, ly, left->x, left->y); nsvg__addEdge(r, right->x, right->y, rx, ry); left->x = lx; left->y = ly; right->x = rx; right->y = ry; } static int nsvg__curveDivs(float r, float arc, float tol) { float da = acosf(r / (r + tol)) * 2.0f; int divs = (int)ceilf(arc / da); if (divs < 2) divs = 2; return divs; } static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) { int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; NSVGpoint* p0, *p1; int j, s, e; // Build stroke edges if (closed) { // Looping p0 = &points[npoints-1]; p1 = &points[0]; s = 0; e = npoints; } else { // Add cap p0 = &points[0]; p1 = &points[1]; s = 1; e = npoints-1; } if (closed) { nsvg__initClosed(&left, &right, p0, p1, lineWidth); firstLeft = left; firstRight = right; } else { // Add cap float dx = p1->x - p0->x; float dy = p1->y - p0->y; nsvg__normalize(&dx, &dy); if (lineCap == NSVG_CAP_BUTT) nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); else if (lineCap == NSVG_CAP_SQUARE) nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); else if (lineCap == NSVG_CAP_ROUND) nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); } for (j = s; j < e; ++j) { if (p1->flags & NSVG_PT_CORNER) { if (lineJoin == NSVG_JOIN_ROUND) nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); else nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); } else { nsvg__straightJoin(r, &left, &right, p1, lineWidth); } p0 = p1++; } if (closed) { // Loop it nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); } else { // Add cap float dx = p1->x - p0->x; float dy = p1->y - p0->y; nsvg__normalize(&dx, &dy); if (lineCap == NSVG_CAP_BUTT) nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); else if (lineCap == NSVG_CAP_SQUARE) nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); else if (lineCap == NSVG_CAP_ROUND) nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); } } static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) { int i, j; NSVGpoint* p0, *p1; p0 = &r->points[r->npoints-1]; p1 = &r->points[0]; for (i = 0; i < r->npoints; i++) { // Calculate segment direction and length p0->dx = p1->x - p0->x; p0->dy = p1->y - p0->y; p0->len = nsvg__normalize(&p0->dx, &p0->dy); // Advance p0 = p1++; } // calculate joins p0 = &r->points[r->npoints-1]; p1 = &r->points[0]; for (j = 0; j < r->npoints; j++) { float dlx0, dly0, dlx1, dly1, dmr2, cross; dlx0 = p0->dy; dly0 = -p0->dx; dlx1 = p1->dy; dly1 = -p1->dx; // Calculate extrusions p1->dmx = (dlx0 + dlx1) * 0.5f; p1->dmy = (dly0 + dly1) * 0.5f; dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; if (dmr2 > 0.000001f) { float s2 = 1.0f / dmr2; if (s2 > 600.0f) { s2 = 600.0f; } p1->dmx *= s2; p1->dmy *= s2; } // Clear flags, but keep the corner. p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; // Keep track of left turns. cross = p1->dx * p0->dy - p0->dx * p1->dy; if (cross > 0.0f) p1->flags |= NSVG_PT_LEFT; // Check to see if the corner needs to be beveled. if (p1->flags & NSVG_PT_CORNER) { if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { p1->flags |= NSVG_PT_BEVEL; } } p0 = p1++; } } static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) { int i, j, closed; NSVGpath* path; NSVGpoint* p0, *p1; float miterLimit = shape->miterLimit; int lineJoin = shape->strokeLineJoin; int lineCap = shape->strokeLineCap; float lineWidth = shape->strokeWidth * scale; for (path = shape->paths; path != NULL; path = path->next) { // Flatten path r->npoints = 0; nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); for (i = 0; i < path->npts-1; i += 3) { float* p = &path->pts[i*2]; nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); } if (r->npoints < 2) continue; closed = path->closed; // If the first and last points are the same, remove the last, mark as closed path. p0 = &r->points[r->npoints-1]; p1 = &r->points[0]; if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { r->npoints--; p0 = &r->points[r->npoints-1]; closed = 1; } if (shape->strokeDashCount > 0) { int idash = 0, dashState = 1; float totalDist = 0, dashLen, allDashLen, dashOffset; NSVGpoint cur; if (closed) nsvg__appendPathPoint(r, r->points[0]); // Duplicate points -> points2. nsvg__duplicatePoints(r); r->npoints = 0; cur = r->points2[0]; nsvg__appendPathPoint(r, cur); // Figure out dash offset. allDashLen = 0; for (j = 0; j < shape->strokeDashCount; j++) allDashLen += shape->strokeDashArray[j]; if (shape->strokeDashCount & 1) allDashLen *= 2.0f; // Find location inside pattern dashOffset = fmodf(shape->strokeDashOffset, allDashLen); if (dashOffset < 0.0f) dashOffset += allDashLen; while (dashOffset > shape->strokeDashArray[idash]) { dashOffset -= shape->strokeDashArray[idash]; idash = (idash + 1) % shape->strokeDashCount; } dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; for (j = 1; j < r->npoints2; ) { float dx = r->points2[j].x - cur.x; float dy = r->points2[j].y - cur.y; float dist = sqrtf(dx*dx + dy*dy); if ((totalDist + dist) > dashLen) { // Calculate intermediate point float d = (dashLen - totalDist) / dist; float x = cur.x + dx * d; float y = cur.y + dy * d; nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); // Stroke if (r->npoints > 1 && dashState) { nsvg__prepareStroke(r, miterLimit, lineJoin); nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); } // Advance dash pattern dashState = !dashState; idash = (idash+1) % shape->strokeDashCount; dashLen = shape->strokeDashArray[idash] * scale; // Restart cur.x = x; cur.y = y; cur.flags = NSVG_PT_CORNER; totalDist = 0.0f; r->npoints = 0; nsvg__appendPathPoint(r, cur); } else { totalDist += dist; cur = r->points2[j]; nsvg__appendPathPoint(r, cur); j++; } } // Stroke any leftover path if (r->npoints > 1 && dashState) nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); } else { nsvg__prepareStroke(r, miterLimit, lineJoin); nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); } } } static int nsvg__cmpEdge(const void *p, const void *q) { const NSVGedge* a = (const NSVGedge*)p; const NSVGedge* b = (const NSVGedge*)q; if (a->y0 < b->y0) return -1; if (a->y0 > b->y0) return 1; return 0; } static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) { NSVGactiveEdge* z; float dxdy; if (r->freelist != NULL) { // Restore from freelist. z = r->freelist; r->freelist = z->next; } else { // Alloc new edge. z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); if (z == NULL) return NULL; } dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); // STBTT_assert(e->y0 <= start_point); // round dx down to avoid going too far if (dxdy < 0) z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); else z->dx = (int)floorf(NSVG__FIX * dxdy); z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); // z->x -= off_x * FIX; z->ey = e->y1; z->next = 0; z->dir = e->dir; return z; } static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) { z->next = r->freelist; r->freelist = z; } static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) { int i = x0 >> NSVG__FIXSHIFT; int j = x1 >> NSVG__FIXSHIFT; if (i < *xmin) *xmin = i; if (j > *xmax) *xmax = j; if (i < len && j >= 0) { if (i == j) { // x0,x1 are the same pixel, so compute combined coverage scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); } else { if (i >= 0) // add antialiasing for x0 scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); else i = -1; // clip if (j < len) // add antialiasing for x1 scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); else j = len; // clip for (++i; i < j; ++i) // fill pixels between x0 and x1 scanline[i] = (unsigned char)(scanline[i] + maxWeight); } } } // note: this routine clips fills that extend off the edges... ideally this // wouldn't happen, but it could happen if the truetype glyph bounding boxes // are wrong, or if the user supplies a too-small bitmap static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) { // non-zero winding fill int x0 = 0, w = 0; if (fillRule == NSVG_FILLRULE_NONZERO) { // Non-zero while (e != NULL) { if (w == 0) { // if we're currently at zero, we need to record the edge start point x0 = e->x; w += e->dir; } else { int x1 = e->x; w += e->dir; // if we went to zero, we need to draw if (w == 0) nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); } e = e->next; } } else if (fillRule == NSVG_FILLRULE_EVENODD) { // Even-odd while (e != NULL) { if (w == 0) { // if we're currently at zero, we need to record the edge start point x0 = e->x; w = 1; } else { int x1 = e->x; w = 0; nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); } e = e->next; } } } static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return (r) | (g << 8) | (b << 16) | (a << 24); } static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) { int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); } static unsigned int nsvg__applyOpacity(unsigned int c, float u) { int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); int r = (c) & 0xff; int g = (c>>8) & 0xff; int b = (c>>16) & 0xff; int a = (((c>>24) & 0xff)*iu) >> 8; return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); } static inline int nsvg__div255(int x) { return ((x+1) * 257) >> 16; } static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, float tx, float ty, float scale, NSVGcachedPaint* cache) { if (cache->type == NSVG_PAINT_COLOR) { int i, cr, cg, cb, ca; cr = cache->colors[0] & 0xff; cg = (cache->colors[0] >> 8) & 0xff; cb = (cache->colors[0] >> 16) & 0xff; ca = (cache->colors[0] >> 24) & 0xff; for (i = 0; i < count; i++) { int r,g,b; int a = nsvg__div255((int)cover[0] * ca); int ia = 255 - a; // Premultiply r = nsvg__div255(cr * a); g = nsvg__div255(cg * a); b = nsvg__div255(cb * a); // Blend over r += nsvg__div255(ia * (int)dst[0]); g += nsvg__div255(ia * (int)dst[1]); b += nsvg__div255(ia * (int)dst[2]); a += nsvg__div255(ia * (int)dst[3]); dst[0] = (unsigned char)r; dst[1] = (unsigned char)g; dst[2] = (unsigned char)b; dst[3] = (unsigned char)a; cover++; dst += 4; } } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { // TODO: spread modes. // TODO: plenty of opportunities to optimize. float fx, fy, dx, gy; float* t = cache->xform; int i, cr, cg, cb, ca; unsigned int c; fx = ((float)x - tx) / scale; fy = ((float)y - ty) / scale; dx = 1.0f / scale; for (i = 0; i < count; i++) { int r,g,b,a,ia; gy = fx*t[1] + fy*t[3] + t[5]; c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; cr = (c) & 0xff; cg = (c >> 8) & 0xff; cb = (c >> 16) & 0xff; ca = (c >> 24) & 0xff; a = nsvg__div255((int)cover[0] * ca); ia = 255 - a; // Premultiply r = nsvg__div255(cr * a); g = nsvg__div255(cg * a); b = nsvg__div255(cb * a); // Blend over r += nsvg__div255(ia * (int)dst[0]); g += nsvg__div255(ia * (int)dst[1]); b += nsvg__div255(ia * (int)dst[2]); a += nsvg__div255(ia * (int)dst[3]); dst[0] = (unsigned char)r; dst[1] = (unsigned char)g; dst[2] = (unsigned char)b; dst[3] = (unsigned char)a; cover++; dst += 4; fx += dx; } } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { // TODO: spread modes. // TODO: plenty of opportunities to optimize. // TODO: focus (fx,fy) float fx, fy, dx, gx, gy, gd; float* t = cache->xform; int i, cr, cg, cb, ca; unsigned int c; fx = ((float)x - tx) / scale; fy = ((float)y - ty) / scale; dx = 1.0f / scale; for (i = 0; i < count; i++) { int r,g,b,a,ia; gx = fx*t[0] + fy*t[2] + t[4]; gy = fx*t[1] + fy*t[3] + t[5]; gd = sqrtf(gx*gx + gy*gy); c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; cr = (c) & 0xff; cg = (c >> 8) & 0xff; cb = (c >> 16) & 0xff; ca = (c >> 24) & 0xff; a = nsvg__div255((int)cover[0] * ca); ia = 255 - a; // Premultiply r = nsvg__div255(cr * a); g = nsvg__div255(cg * a); b = nsvg__div255(cb * a); // Blend over r += nsvg__div255(ia * (int)dst[0]); g += nsvg__div255(ia * (int)dst[1]); b += nsvg__div255(ia * (int)dst[2]); a += nsvg__div255(ia * (int)dst[3]); dst[0] = (unsigned char)r; dst[1] = (unsigned char)g; dst[2] = (unsigned char)b; dst[3] = (unsigned char)a; cover++; dst += 4; fx += dx; } } } static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) { NSVGactiveEdge *active = NULL; int y, s; int e = 0; int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline int xmin, xmax; for (y = 0; y < r->height; y++) { memset(r->scanline, 0, r->width); xmin = r->width; xmax = 0; for (s = 0; s < NSVG__SUBSAMPLES; ++s) { // find center of pixel for this scanline float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; NSVGactiveEdge **step = &active; // update all active edges; // remove all active edges that terminate before the center of this scanline while (*step) { NSVGactiveEdge *z = *step; if (z->ey <= scany) { *step = z->next; // delete from list // NSVG__assert(z->valid); nsvg__freeActive(r, z); } else { z->x += z->dx; // advance to position for current scanline step = &((*step)->next); // advance through list } } // resort the list if needed for (;;) { int changed = 0; step = &active; while (*step && (*step)->next) { if ((*step)->x > (*step)->next->x) { NSVGactiveEdge* t = *step; NSVGactiveEdge* q = t->next; t->next = q->next; q->next = t; *step = q; changed = 1; } step = &(*step)->next; } if (!changed) break; } // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline while (e < r->nedges && r->edges[e].y0 <= scany) { if (r->edges[e].y1 > scany) { NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); if (z == NULL) break; // find insertion point if (active == NULL) { active = z; } else if (z->x < active->x) { // insert at front z->next = active; active = z; } else { // find thing to insert AFTER NSVGactiveEdge* p = active; while (p->next && p->next->x < z->x) p = p->next; // at this point, p->next->x is NOT < z->x z->next = p->next; p->next = z; } } e++; } // now process all active edges in non-zero fashion if (active != NULL) nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); } // Blit if (xmin < 0) xmin = 0; if (xmax > r->width-1) xmax = r->width-1; if (xmin <= xmax) { nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); } } } static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) { int x,y; // Unpremultiply for (y = 0; y < h; y++) { unsigned char *row = &image[y*stride]; for (x = 0; x < w; x++) { int r = row[0], g = row[1], b = row[2], a = row[3]; if (a != 0) { row[0] = (unsigned char)(r*255/a); row[1] = (unsigned char)(g*255/a); row[2] = (unsigned char)(b*255/a); } row += 4; } } // Defringe for (y = 0; y < h; y++) { unsigned char *row = &image[y*stride]; for (x = 0; x < w; x++) { int r = 0, g = 0, b = 0, a = row[3], n = 0; if (a == 0) { if (x-1 > 0 && row[-1] != 0) { r += row[-4]; g += row[-3]; b += row[-2]; n++; } if (x+1 < w && row[7] != 0) { r += row[4]; g += row[5]; b += row[6]; n++; } if (y-1 > 0 && row[-stride+3] != 0) { r += row[-stride]; g += row[-stride+1]; b += row[-stride+2]; n++; } if (y+1 < h && row[stride+3] != 0) { r += row[stride]; g += row[stride+1]; b += row[stride+2]; n++; } if (n > 0) { row[0] = (unsigned char)(r/n); row[1] = (unsigned char)(g/n); row[2] = (unsigned char)(b/n); } } row += 4; } } } static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) { int i, j; NSVGgradient* grad; cache->type = paint->type; if (paint->type == NSVG_PAINT_COLOR) { cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); return; } grad = paint->gradient; cache->spread = grad->spread; memcpy(cache->xform, grad->xform, sizeof(float)*6); if (grad->nstops == 0) { for (i = 0; i < 256; i++) cache->colors[i] = 0; } if (grad->nstops == 1) { for (i = 0; i < 256; i++) cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); } else { unsigned int ca, cb = 0; float ua, ub, du, u; int ia, ib, count; ca = nsvg__applyOpacity(grad->stops[0].color, opacity); ua = nsvg__clampf(grad->stops[0].offset, 0, 1); ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); ia = (int)(ua * 255.0f); ib = (int)(ub * 255.0f); for (i = 0; i < ia; i++) { cache->colors[i] = ca; } for (i = 0; i < grad->nstops-1; i++) { ca = nsvg__applyOpacity(grad->stops[i].color, opacity); cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); ua = nsvg__clampf(grad->stops[i].offset, 0, 1); ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); ia = (int)(ua * 255.0f); ib = (int)(ub * 255.0f); count = ib - ia; if (count <= 0) continue; u = 0; du = 1.0f / (float)count; for (j = 0; j < count; j++) { cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); u += du; } } for (i = ib; i < 256; i++) cache->colors[i] = cb; } } /* static void dumpEdges(NSVGrasterizer* r, const char* name) { float xmin = 0, xmax = 0, ymin = 0, ymax = 0; NSVGedge *e = NULL; int i; if (r->nedges == 0) return; FILE* fp = fopen(name, "w"); if (fp == NULL) return; xmin = xmax = r->edges[0].x0; ymin = ymax = r->edges[0].y0; for (i = 0; i < r->nedges; i++) { e = &r->edges[i]; xmin = nsvg__minf(xmin, e->x0); xmin = nsvg__minf(xmin, e->x1); xmax = nsvg__maxf(xmax, e->x0); xmax = nsvg__maxf(xmax, e->x1); ymin = nsvg__minf(ymin, e->y0); ymin = nsvg__minf(ymin, e->y1); ymax = nsvg__maxf(ymax, e->y0); ymax = nsvg__maxf(ymax, e->y1); } fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin)); for (i = 0; i < r->nedges; i++) { e = &r->edges[i]; fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1); } for (i = 0; i < r->npoints; i++) { if (i+1 < r->npoints) fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#f00;\" />", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); fprintf(fp ,"<circle cx=\"%f\" cy=\"%f\" r=\"1\" style=\"fill:%s;\" />", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); } fprintf(fp, "</svg>"); fclose(fp); } */ NANOSVG_SCOPE void nsvgRasterize(NSVGrasterizer* r, NSVGimage* image, float tx, float ty, float scale, unsigned char* dst, int w, int h, int stride) { NSVGshape *shape = NULL; NSVGedge *e = NULL; NSVGcachedPaint cache; int i; r->bitmap = dst; r->width = w; r->height = h; r->stride = stride; if (w > r->cscanline) { r->cscanline = w; r->scanline = (unsigned char*)NANOSVG_realloc(r->scanline, w); if (r->scanline == NULL) return; } for (i = 0; i < h; i++) memset(&dst[i*stride], 0, w*4); for (shape = image->shapes; shape != NULL; shape = shape->next) { if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue; if (shape->fill.type != NSVG_PAINT_NONE) { nsvg__resetPool(r); r->freelist = NULL; r->nedges = 0; nsvg__flattenShape(r, shape, scale); // Scale and translate edges for (i = 0; i < r->nedges; i++) { e = &r->edges[i]; e->x0 = tx + e->x0; e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; e->x1 = tx + e->x1; e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; } // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule nsvg__initPaint(&cache, &shape->fill, shape->opacity); nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); } if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { nsvg__resetPool(r); r->freelist = NULL; r->nedges = 0; nsvg__flattenShapeStroke(r, shape, scale); // dumpEdges(r, "edge.svg"); // Scale and translate edges for (i = 0; i < r->nedges; i++) { e = &r->edges[i]; e->x0 = tx + e->x0; e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; e->x1 = tx + e->x1; e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; } // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule nsvg__initPaint(&cache, &shape->stroke, shape->opacity); nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); } } nsvg__unpremultiplyAlpha(dst, w, h, stride); r->bitmap = NULL; r->width = 0; r->height = 0; r->stride = 0; } #endif |
Changes to generic/tk.h.
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | int height); typedef double (Tk_ItemPointProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); typedef int (Tk_ItemAreaProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); typedef int (Tk_ItemPostscriptProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); typedef void (Tk_ItemScaleProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); typedef void (Tk_ItemTranslateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); #ifdef USE_OLD_CANVAS typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, | > > | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | int height); typedef double (Tk_ItemPointProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); typedef int (Tk_ItemAreaProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); typedef int (Tk_ItemPostscriptProc)(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); typedef void (Tk_ItemRotateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRadians); typedef void (Tk_ItemScaleProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); typedef void (Tk_ItemTranslateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); #ifdef USE_OLD_CANVAS typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 | 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. */ | > > | | 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | 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. */ Tk_ItemRotateProc *rotateProc; /* Procedure to rotate an item's coordinates * about a point. */ int reserved2; /* Carefully compatible with */ char *reserved3; /* Jan Nijtmans dash patch */ char *reserved4; } Tk_ItemType; /* * Flag (used in the alwaysRedraw field) to say whether an item supports |
︙ | ︙ |
Changes to generic/tkButton.c.
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 | /* * If a radiobutton has the empty string as value it should be * selected. */ if ((butPtr->type == TYPE_RADIO_BUTTON) && | | | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | /* * If a radiobutton has the empty string as value it should be * selected. */ if ((butPtr->type == TYPE_RADIO_BUTTON) && (*Tcl_GetString(butPtr->onValuePtr) == '\0')) { butPtr->flags |= SELECTED; } } } /* * Get the images for the widget, if there are any. Allocate the new |
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 | const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register TkButton *butPtr = clientData; const char *value; Tcl_Obj *valuePtr; | < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 | const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register TkButton *butPtr = clientData; const char *value; Tcl_Obj *valuePtr; /* * 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 | TRISTATED); if (!Tcl_InterpDeleted(interp)) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, Tcl_GetString(butPtr->selVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonVarProc, probe); if (probe == (ClientData)butPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * selVarNamePtr, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ goto redisplay; } Tcl_TraceVar2(interp, Tcl_GetString(butPtr->selVarNamePtr), NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonVarProc, clientData); } goto redisplay; } |
︙ | ︙ | |||
1707 1708 1709 1710 1711 1712 1713 | */ /* ARGSUSED */ static char * ButtonTextVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ | | | < < < < < < < < < < < < < > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 | */ /* ARGSUSED */ static char * ButtonTextVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ const char *name1, /* Not used. */ const char *name2, /* Not used. */ int flags) /* Information about what happened. */ { TkButton *butPtr = clientData; Tcl_Obj *valuePtr; if (butPtr->flags & BUTTON_DELETED) { return NULL; } /* * If the variable is unset, then immediately recreate it unless the whole * interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && butPtr->textVarNamePtr != NULL) { /* * An unset trace on some variable brought us here, but is it * the variable we have stored in butPtr->textVarNamePtr ? */ ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, Tcl_GetString(butPtr->textVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, probe); if (probe == (ClientData)butPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * textVarNamePtr, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former textvariable must be, and we should ignore it. */ return NULL; } Tcl_ObjSetVar2(interp, butPtr->textVarNamePtr, NULL, butPtr->textPtr, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, Tcl_GetString(butPtr->textVarNamePtr), NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, clientData); } return NULL; |
︙ | ︙ |
Changes to generic/tkCanvArc.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkCanvas.h" /* * The structure below defines the record for each arc item. */ typedef enum { PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE } Style; | > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkCanvas.h" #include "float.h" /* * The structure below defines the record for each arc item. */ typedef enum { PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE } Style; |
︙ | ︙ | |||
179 180 181 182 183 184 185 | * Prototypes for functions defined in this file: */ static void ComputeArcBbox(Tk_Canvas canvas, ArcItem *arcPtr); static int ConfigureArc(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[], int flags); | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | * Prototypes for functions defined in this file: */ static void ComputeArcBbox(Tk_Canvas canvas, ArcItem *arcPtr); static int ConfigureArc(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[], int flags); static void ComputeArcParametersFromHeight(ArcItem *arcPtr); static int CreateArc(Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteArc(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayArc(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, |
︙ | ︙ | |||
210 211 212 213 214 215 216 217 218 219 220 221 222 223 | static void ComputeArcOutline(Tk_Canvas canvas, ArcItem *arcPtr); static int HorizLineToArc(double x1, double x2, double y, double rx, double ry, double start, double extent); static int VertLineToArc(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 functions that * can be invoked by generic item code. */ Tk_ItemType tkArcType = { | > > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | static void ComputeArcOutline(Tk_Canvas canvas, ArcItem *arcPtr); static int HorizLineToArc(double x1, double x2, double y, double rx, double ry, double start, double extent); static int VertLineToArc(double x, double y1, double y2, double rx, double ry, double start, double extent); static void RotateArc(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); /* * The structures below defines the arc item types by means of functions that * can be invoked by generic item code. */ Tk_ItemType tkArcType = { |
︙ | ︙ | |||
237 238 239 240 241 242 243 | TranslateArc, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | TranslateArc, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateArc, /* rotateProc */ 0, NULL, NULL }; /* *-------------------------------------------------------------- * * CreateArc -- * |
︙ | ︙ | |||
465 466 467 468 469 470 471 | arcPtr->activeFillStipple != None) { itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; } /* | | < | | < | > | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | arcPtr->activeFillStipple != None) { itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; } /* * Override the start and extent if the height is given. */ ComputeArcParametersFromHeight(arcPtr); ComputeArcBbox(canvas, arcPtr); 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); |
︙ | ︙ | |||
585 586 587 588 589 590 591 | ComputeArcBbox(canvas, arcPtr); return TCL_OK; } /* *-------------------------------------------------------------- * | | | > > | > > > > > > > > > > > | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | ComputeArcBbox(canvas, arcPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * ComputeArcParametersFromHeight -- * * This function calculates the arc parameters given start-point, * end-point and height (!= 0). * * Results: * None. * * Side effects: * The height parameter is set to 0 on exit. * *-------------------------------------------------------------- */ static void ComputeArcParametersFromHeight( ArcItem* arcPtr) { double chordLen, chordDir[2], chordCen[2], arcCen[2], d, radToDeg, radius; /* * Do nothing if no height has been specified. */ if (arcPtr->height == 0) return; /* * Calculate the chord length, return early if it is too small. */ chordLen = hypot(arcPtr->endPoint[1] - arcPtr->startPoint[1], arcPtr->startPoint[0] - arcPtr->endPoint[0]); if (chordLen < DBL_EPSILON) { arcPtr->start = arcPtr->extent = arcPtr->height = 0; return; } chordDir[0] = (arcPtr->endPoint[0] - arcPtr->startPoint[0]) / chordLen; chordDir[1] = (arcPtr->endPoint[1] - arcPtr->startPoint[1]) / chordLen; chordCen[0] = (arcPtr->startPoint[0] + arcPtr->endPoint[0]) / 2; chordCen[1] = (arcPtr->startPoint[1] + arcPtr->endPoint[1]) / 2; /* * Calculate the radius (assumes height != 0). |
︙ | ︙ | |||
787 788 789 790 791 792 793 | arcPtr->bbox[2] = arcPtr->bbox[0]; arcPtr->bbox[0] = tmp; } ComputeArcOutline(canvas,arcPtr); /* | | | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | arcPtr->bbox[2] = arcPtr->bbox[0]; arcPtr->bbox[0] = tmp; } ComputeArcOutline(canvas,arcPtr); /* * To compute the bounding box, start with 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]; |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 | { 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 -- | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 | { 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); } /* *-------------------------------------------------------------- * * RotateArc -- * * This function is called to rotate an arc by a given amount. * * Results: * None. * * Side effects: * The position of the arc is rotated by angleRad radians about (originX, * originY), and the bounding box is updated in the generic part of the * item structure. * *-------------------------------------------------------------- */ static void RotateArc( Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad) { ArcItem *arcPtr = (ArcItem *) itemPtr; double newX, newY, oldX, oldY; /* * Compute the centre of the box, then rotate that about the origin. */ newX = oldX = (arcPtr->bbox[0] + arcPtr->bbox[2]) / 2.0; newY = oldY = (arcPtr->bbox[1] + arcPtr->bbox[3]) / 2.0; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &newX, &newY); /* * Apply the translation to the box. */ arcPtr->bbox[0] += newX - oldX; arcPtr->bbox[1] += newY - oldY; arcPtr->bbox[2] += newX - oldX; arcPtr->bbox[3] += newY - oldY; /* * TODO: update the arc endpoints? */ ComputeArcBbox(canvas, arcPtr); } /* *-------------------------------------------------------------- * * TranslateArc -- |
︙ | ︙ |
Changes to generic/tkCanvBmap.c.
︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void ScaleBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* | > > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void RotateBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScaleBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateBitmap(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* |
︙ | ︙ | |||
133 134 135 136 137 138 139 | TranslateBitmap, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | TranslateBitmap, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateBitmap, /* rotateProc */ 0, NULL, NULL }; /* *-------------------------------------------------------------- * * TkcCreateBitmap -- * |
︙ | ︙ | |||
782 783 784 785 786 787 788 789 790 791 792 793 794 795 | { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; bmapPtr->x = originX + scaleX*(bmapPtr->x - originX); bmapPtr->y = originY + scaleY*(bmapPtr->y - originY); ComputeBitmapBbox(canvas, bmapPtr); } /* *-------------------------------------------------------------- * * TranslateBitmap -- * * This function is called to move an item by a given amount. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; bmapPtr->x = originX + scaleX*(bmapPtr->x - originX); bmapPtr->y = originY + scaleY*(bmapPtr->y - originY); ComputeBitmapBbox(canvas, bmapPtr); } /* *-------------------------------------------------------------- * * RotateBitmap -- * * This function is called to rotate a bitmap's origin by a given amount. * * Results: * None. * * Side effects: * The position of the bitmap is rotated by angleRad radians about * (originX, originY), and the bounding box is updated in the generic * part of the item structure. * *-------------------------------------------------------------- */ static void RotateBitmap( Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad) { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &bmapPtr->x, &bmapPtr->y); ComputeBitmapBbox(canvas, bmapPtr); } /* *-------------------------------------------------------------- * * TranslateBitmap -- * * This function is called to move an item by a given amount. |
︙ | ︙ |
Changes to generic/tkCanvImg.c.
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 99 100 101 102 103 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int argc, Tcl_Obj *const argv[]); static void DeleteImage(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayImage(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void ScaleImage(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateImage(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* | > > | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int argc, Tcl_Obj *const argv[]); static void DeleteImage(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayImage(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void RotateImage(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScaleImage(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateImage(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* |
︙ | ︙ | |||
122 123 124 125 126 127 128 | TranslateImage, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | TranslateImage, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateImage, /* rotateProc */ 0, NULL, NULL }; /* *-------------------------------------------------------------- * * CreateImage -- * |
︙ | ︙ | |||
753 754 755 756 757 758 759 760 761 762 763 764 765 766 | Tcl_AppendPrintfToObj(psObj, "%.15g %.15g translate\n", x, y); } return Tk_PostscriptImage(image, interp, canvasWin, ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); } /* *-------------------------------------------------------------- * * ScaleImage -- * * This function is invoked to rescale an item. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | Tcl_AppendPrintfToObj(psObj, "%.15g %.15g translate\n", x, y); } return Tk_PostscriptImage(image, interp, canvasWin, ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); } /* *-------------------------------------------------------------- * * RotateImage -- * * This function is called to rotate an image's origin by a given amount. * This does *not* rotate the contents of the image. * * Results: * None. * * Side effects: * The position of the image anchor is rotated by angleRad radians about * (originX, originY), and the bounding box is updated in the generic * part of the item structure. * *-------------------------------------------------------------- */ static void RotateImage( Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad) { ImageItem *imgPtr = (ImageItem *) itemPtr; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &imgPtr->x, &imgPtr->y); ComputeImageBbox(canvas, imgPtr); } /* *-------------------------------------------------------------- * * ScaleImage -- * * This function is invoked to rescale an item. |
︙ | ︙ |
Changes to generic/tkCanvLine.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 | Tcl_FreeProc **freeProcPtr); static int ParseArrowShape(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, const char *value, char *recordPtr, int offset); static const char * PrintArrowShape(ClientData clientData, Tk_Window tkwin, char *recordPtr, int offset, Tcl_FreeProc **freeProcPtr); static void ScaleLine(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateLine(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* | > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Tcl_FreeProc **freeProcPtr); static int ParseArrowShape(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, const char *value, char *recordPtr, int offset); static const char * PrintArrowShape(ClientData clientData, Tk_Window tkwin, char *recordPtr, int offset, Tcl_FreeProc **freeProcPtr); static void RotateLine(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScaleLine(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateLine(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* |
︙ | ︙ | |||
235 236 237 238 239 240 241 | TranslateLine, /* translateProc */ GetLineIndex, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ LineInsert, /* insertProc */ LineDeleteCoords, /* dTextProc */ NULL, /* nextPtr */ | > | | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | TranslateLine, /* translateProc */ GetLineIndex, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ LineInsert, /* insertProc */ LineDeleteCoords, /* dTextProc */ NULL, /* nextPtr */ RotateLine, /* rotateProc */ 0, NULL, 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). */ |
︙ | ︙ | |||
1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 | } 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); } /* *-------------------------------------------------------------- * | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 | } 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); } /* *-------------------------------------------------------------- * * RotateLine -- * * This function is called to rotate a line by a given amount about a * point. * * Results: * None. * * Side effects: * The position of the line is rotated by angleRad about (originX, * originY), and the bounding box is updated in the generic part of the * item structure. * *-------------------------------------------------------------- */ static void RotateLine( Tk_Canvas canvas, /* Canvas containing item. */ Tk_Item *itemPtr, /* Item that is being moved. */ double originX, double originY, double angleRad) /* Amount by which item is to be rotated. */ { LineItem *linePtr = (LineItem *) itemPtr; double *coordPtr; int i; double s = sin(angleRad), c = cos(angleRad); for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints; i++, coordPtr += 2) { TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]); } if (linePtr->firstArrowPtr != NULL) { for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]); } } if (linePtr->lastArrowPtr != NULL) { for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]); } } ComputeLineBbox(canvas, linePtr); } /* *-------------------------------------------------------------- * |
︙ | ︙ |
Changes to generic/tkCanvPoly.c.
︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj); static int PolygonToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); static double PolygonToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static int PolygonToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static void ScalePolygon(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslatePolygon(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* | > > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj); static int PolygonToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); static double PolygonToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static int PolygonToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static void RotatePolygon(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScalePolygon(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslatePolygon(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* |
︙ | ︙ | |||
198 199 200 201 202 203 204 | DisplayPolygon, /* displayProc */ TK_CONFIG_OBJS | TK_MOVABLE_POINTS, /* flags */ PolygonToPoint, /* pointProc */ PolygonToArea, /* areaProc */ PolygonToPostscript, /* postscriptProc */ ScalePolygon, /* scaleProc */ TranslatePolygon, /* translateProc */ | | | > | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | DisplayPolygon, /* displayProc */ TK_CONFIG_OBJS | TK_MOVABLE_POINTS, /* flags */ PolygonToPoint, /* pointProc */ PolygonToArea, /* areaProc */ PolygonToPostscript, /* postscriptProc */ ScalePolygon, /* scaleProc */ TranslatePolygon, /* translateProc */ GetPolygonIndex, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ PolygonInsert, /* insertProc */ PolygonDeleteCoords, /* dTextProc */ NULL, /* nextPtr */ RotatePolygon, /* rotateProc */ 0, NULL, 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). */ |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | */ badIndex: Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad index \"%s\"", string)); Tcl_SetErrorCode(interp, "TK", "CANVAS", "ITEM_INDEX", "POLY", NULL); return TCL_ERROR; } /* *-------------------------------------------------------------- * * TranslatePolygon -- * * This function is called to move a polygon by a given amount. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | */ badIndex: Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad index \"%s\"", string)); Tcl_SetErrorCode(interp, "TK", "CANVAS", "ITEM_INDEX", "POLY", NULL); return TCL_ERROR; } /* *-------------------------------------------------------------- * * RotatePolygon -- * * This function is called to rotate a polygon by a given amount about a * point. * * Results: * None. * * Side effects: * The position of the polygon is rotated by angleRad about (originX, * originY), and the bounding box is updated in the generic part of the * item structure. * *-------------------------------------------------------------- */ static void RotatePolygon( Tk_Canvas canvas, /* Canvas containing item. */ Tk_Item *itemPtr, /* Item that is being moved. */ double originX, double originY, double angleRad) /* Amount by which item is to be rotated. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; double *coordPtr; int i; double s = sin(angleRad), c = cos(angleRad); for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; i++, coordPtr += 2) { TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]); } ComputePolygonBbox(canvas, polyPtr); } /* *-------------------------------------------------------------- * * TranslatePolygon -- * * This function is called to move a polygon by a given amount. |
︙ | ︙ |
Changes to generic/tkCanvText.c.
︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 | Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj); static int TextToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); static double TextToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static int TextToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static void TranslateText(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* * The structures below defines the rectangle and oval item types by means of * functions that can be invoked by generic item code. */ | > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj); static int TextToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr); static double TextToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static int TextToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static void RotateText(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void TranslateText(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* * The structures below defines the rectangle and oval item types by means of * functions that can be invoked by generic item code. */ |
︙ | ︙ | |||
195 196 197 198 199 200 201 | TranslateText, /* translateProc */ GetTextIndex, /* indexProc */ SetTextCursor, /* icursorProc */ GetSelText, /* selectionProc */ TextInsert, /* insertProc */ TextDeleteChars, /* dTextProc */ NULL, /* nextPtr */ | > | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | TranslateText, /* translateProc */ GetTextIndex, /* indexProc */ SetTextCursor, /* icursorProc */ GetSelText, /* selectionProc */ TextInsert, /* insertProc */ TextDeleteChars, /* dTextProc */ NULL, /* nextPtr */ RotateText, /* rotateProc */ 0, NULL, NULL }; #define ROUND(d) ((int) floor((d) + 0.5)) /* *-------------------------------------------------------------- * |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | return TkIntersectAngledTextLayout(textPtr->textLayout, (int) ((rectPtr[0] + 0.5) - textPtr->drawOrigin[0]), (int) ((rectPtr[1] + 0.5) - textPtr->drawOrigin[1]), (int) (rectPtr[2] - rectPtr[0] + 0.5), (int) (rectPtr[3] - rectPtr[1] + 0.5), textPtr->angle); } /* *-------------------------------------------------------------- * * ScaleText -- * * This function is invoked to rescale a text item. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | return TkIntersectAngledTextLayout(textPtr->textLayout, (int) ((rectPtr[0] + 0.5) - textPtr->drawOrigin[0]), (int) ((rectPtr[1] + 0.5) - textPtr->drawOrigin[1]), (int) (rectPtr[2] - rectPtr[0] + 0.5), (int) (rectPtr[3] - rectPtr[1] + 0.5), textPtr->angle); } /* *-------------------------------------------------------------- * * RotateText -- * * This function is called to rotate a text item by a given amount about a * point. Note that this does *not* rotate the text of the item. * * Results: * None. * * Side effects: * The position of the text anchor is rotated by angleRad about (originX, * originY), and the bounding box is updated in the generic part of the * item structure. * *-------------------------------------------------------------- */ static void RotateText( Tk_Canvas canvas, /* Canvas containing item. */ Tk_Item *itemPtr, /* Item that is being rotated. */ double originX, double originY, double angleRad) /* Amount by which item is to be rotated. */ { TextItem *textPtr = (TextItem *) itemPtr; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &textPtr->x, &textPtr->y); ComputeTextBbox(canvas, textPtr); } /* *-------------------------------------------------------------- * * ScaleText -- * * This function is invoked to rescale a text item. |
︙ | ︙ |
Changes to generic/tkCanvUtil.c.
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | Tk_CanvasSetOffset(canvas, outline->gc, tsoffset); tsoffset->xoffset += w; tsoffset->yoffset += h; return 1; } return 0; } | < | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 | Tk_CanvasSetOffset(canvas, outline->gc, tsoffset); tsoffset->xoffset += w; tsoffset->yoffset += h; return 1; } return 0; } /* *-------------------------------------------------------------- * * Tk_ResetOutlineGC * * Restores the GC to the situation before Tk_ChangeOutlineGC() was |
︙ | ︙ | |||
1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 | TranslateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i); } if (tempArr != staticSpace) { ckfree(tempArr); } return numOutput; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 | TranslateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i); } if (tempArr != staticSpace) { ckfree(tempArr); } return numOutput; } /* *-------------------------------------------------------------- * * TkRotatePoint -- * * Rotate a point about another point. The angle should be converted into * its sine and cosine before calling this function. * * Results: * None * * Side effects: * The point in (*xPtr,*yPtr) is updated to be rotated about * (originX,originY) by the amount given by the sine and cosine of the * angle to rotate. * *-------------------------------------------------------------- */ void TkRotatePoint( double originX, double originY, /* The point about which to rotate. */ double sine, double cosine, /* How much to rotate? */ double *xPtr, double *yPtr) /* The point to be rotated. (INOUT) */ { double x = *xPtr - originX; double y = *yPtr - originY; /* * Beware! The canvas coordinate space is flipped vertically, so rotations * go the "wrong" way with respect to mathematics. */ *xPtr = originX + x * cosine + y * sine; *yPtr = originY - x * sine + y * cosine; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tkCanvWind.c.
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void ScaleWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); static int WinItemCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, | > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); static void DisplayWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height); static void RotateWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScaleWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateWinItem(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); static int WinItemCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, |
︙ | ︙ | |||
126 127 128 129 130 131 132 | TranslateWinItem, /* translateProc */ NULL, /* indexProc */ NULL, /* cursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | TranslateWinItem, /* translateProc */ NULL, /* indexProc */ NULL, /* cursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateWinItem, /* rotateProc */ 0, NULL, NULL }; /* * The structure below defines the official type record for the canvas (as * geometry manager): */ |
︙ | ︙ | |||
907 908 909 910 911 912 913 914 915 916 917 918 919 920 | Tcl_AppendObjToObj(Tcl_GetObjResult(interp), psObj); } else { Tcl_DiscardInterpState(interpState); } Tcl_DecrRefCount(psObj); return result; } /* *-------------------------------------------------------------- * * ScaleWinItem -- * * This function is invoked to rescale a window item. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 | Tcl_AppendObjToObj(Tcl_GetObjResult(interp), psObj); } else { Tcl_DiscardInterpState(interpState); } Tcl_DecrRefCount(psObj); return result; } /* *-------------------------------------------------------------- * * RotateWinItem -- * * This function is called to rotate a window item by a given amount * about a point. Note that this does *not* rotate the window of the * item. * * Results: * None. * * Side effects: * The position of the window anchor is rotated by angleRad about (originX, * originY), and the bounding box is updated in the generic part of the * item structure. * *-------------------------------------------------------------- */ static void RotateWinItem( Tk_Canvas canvas, /* Canvas containing item. */ Tk_Item *itemPtr, /* Item that is being rotated. */ double originX, double originY, double angleRad) /* Amount by which item is to be rotated. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &winItemPtr->x, &winItemPtr->y); ComputeWindowBbox(canvas, winItemPtr); } /* *-------------------------------------------------------------- * * ScaleWinItem -- * * This function is invoked to rescale a window item. |
︙ | ︙ |
Changes to generic/tkCanvas.c.
︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 246 247 248 249 250 | static int CanvasWidgetCmd(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv); static void CanvasWorldChanged(ClientData instanceData); static int ConfigureCanvas(Tcl_Interp *interp, TkCanvas *canvasPtr, int argc, Tcl_Obj *const *argv, int flags); static void DestroyCanvas(void *memPtr); static int DrawCanvas(Tcl_Interp *interp, ClientData clientData, Tk_PhotoHandle photohandle, int subsample, int zoom); static void DisplayCanvas(ClientData clientData); static void DoItem(Tcl_Obj *accumObj, Tk_Item *itemPtr, Tk_Uid tag); static void EventuallyRedrawItem(TkCanvas *canvasPtr, Tk_Item *itemPtr); | > > > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | static int CanvasWidgetCmd(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *argv); static void CanvasWorldChanged(ClientData instanceData); static int ConfigureCanvas(Tcl_Interp *interp, TkCanvas *canvasPtr, int argc, Tcl_Obj *const *argv, int flags); static void DefaultRotateImplementation(TkCanvas *canvasPtr, Tk_Item *itemPtr, double x, double y, double angleRadians); static void DestroyCanvas(void *memPtr); static int DrawCanvas(Tcl_Interp *interp, ClientData clientData, Tk_PhotoHandle photohandle, int subsample, int zoom); static void DisplayCanvas(ClientData clientData); static void DoItem(Tcl_Obj *accumObj, Tk_Item *itemPtr, Tk_Uid tag); static void EventuallyRedrawItem(TkCanvas *canvasPtr, Tk_Item *itemPtr); |
︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 568 569 | Tk_Item *itemPtr, double xDelta, double yDelta) { itemPtr->typePtr->translateProc((Tk_Canvas) canvasPtr, itemPtr, xDelta, yDelta); } /* *-------------------------------------------------------------- * * Tk_CanvasObjCmd -- * * This function is invoked to process the "canvas" Tcl command. See the | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | Tk_Item *itemPtr, double xDelta, double yDelta) { itemPtr->typePtr->translateProc((Tk_Canvas) canvasPtr, itemPtr, xDelta, yDelta); } static inline void ItemRotate( TkCanvas *canvasPtr, Tk_Item *itemPtr, double x, double y, double angleRadians) { if (itemPtr->typePtr->rotateProc != NULL) { itemPtr->typePtr->rotateProc((Tk_Canvas) canvasPtr, itemPtr, x, y, angleRadians); } else { DefaultRotateImplementation(canvasPtr, itemPtr, x, y, angleRadians); } } /* *-------------------------------------------------------------- * * DefaultRotateImplementation -- * * The default implementation of the rotation operation, used when items * do not provide their own version. * *-------------------------------------------------------------- */ static void DefaultRotateImplementation( TkCanvas *canvasPtr, Tk_Item *itemPtr, double x, double y, double angleRadians) { int objc, i, ok = 1; Tcl_Obj **objv, **newObjv; double *coordv; double s = sin(angleRadians); double c = cos(angleRadians); Tcl_Interp *interp = canvasPtr->interp; /* * Get the coordinates out of the item. */ if (ItemCoords(canvasPtr, itemPtr, 0, NULL) == TCL_OK && Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), &objc, &objv) == TCL_OK) { coordv = (double *) Tcl_Alloc(sizeof(double) * objc); for (i=0 ; i<objc ; i++) { if (Tcl_GetDoubleFromObj(NULL, objv[i], &coordv[i]) != TCL_OK) { ok = 0; break; } } if (ok) { /* * Apply the rotation. */ for (i=0 ; i<objc ; i+=2) { double px = coordv[i+0] - x; double py = coordv[i+1] - y; double nx = px * c - py * s; double ny = px * s + py * c; coordv[i+0] = nx + x; coordv[i+1] = ny + y; } /* * Write the coordinates back into the item. */ newObjv = (Tcl_Obj **) Tcl_Alloc(sizeof(Tcl_Obj *) * objc); for (i=0 ; i<objc ; i++) { newObjv[i] = Tcl_NewDoubleObj(coordv[i]); Tcl_IncrRefCount(newObjv[i]); } ItemCoords(canvasPtr, itemPtr, objc, newObjv); for (i=0 ; i<objc ; i++) { Tcl_DecrRefCount(newObjv[i]); } Tcl_Free((char *) newObjv); } Tcl_Free((char *) coordv); } /* * The interpreter result was (probably) modified above; reset it. */ Tcl_ResetResult(interp); } /* *-------------------------------------------------------------- * * Tk_CanvasObjCmd -- * * This function is invoked to process the "canvas" Tcl command. See the |
︙ | ︙ | |||
742 743 744 745 746 747 748 | int index; static const char *const optionStrings[] = { "addtag", "bbox", "bind", "canvasx", "canvasy", "cget", "configure", "coords", "create", "dchars", "delete", "dtag", "find", "focus", "gettags", "icursor", | < | | | | | < | | | | > | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | int index; static const char *const optionStrings[] = { "addtag", "bbox", "bind", "canvasx", "canvasy", "cget", "configure", "coords", "create", "dchars", "delete", "dtag", "find", "focus", "gettags", "icursor", "image", "imove", "index", "insert", "itemcget", "itemconfigure", "lower", "move", "moveto", "postscript", "raise", "rchars", "rotate", "scale", "scan", "select", "type", "xview", "yview", NULL }; enum options { CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX, CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS, CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG, CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR, CANV_IMAGE, CANV_IMOVE, CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, CANV_ITEMCONFIGURE, CANV_LOWER, CANV_MOVE, CANV_MOVETO, CANV_POSTSCRIPT, CANV_RAISE, CANV_RCHARS, CANV_ROTATE, CANV_SCALE, CANV_SCAN, CANV_SELECT, CANV_TYPE, CANV_XVIEW, CANV_YVIEW }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, |
︙ | ︙ | |||
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 | if (!(dontRedraw1 && dontRedraw2)) { Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x1, y1, x2, y2); EventuallyRedrawItem(canvasPtr, itemPtr); } itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } break; } case CANV_SCALE: { double xOrigin, yOrigin, xScale, yScale; if (objc != 7) { Tcl_WrongNumArgs(interp, 2, objv, | > > > > > > > > > > > > > > > > > > > > > > > > | 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 | if (!(dontRedraw1 && dontRedraw2)) { Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x1, y1, x2, y2); EventuallyRedrawItem(canvasPtr, itemPtr); } itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } break; } case CANV_ROTATE: { double x, y, angle; Tk_Canvas canvas = (Tk_Canvas) canvasPtr; if (objc != 6) { Tcl_WrongNumArgs(interp, 2, objv, "tagOrId x y angle"); result = TCL_ERROR; goto done; } if (Tk_CanvasGetCoordFromObj(interp, canvas, objv[3], &x) != TCL_OK || Tk_CanvasGetCoordFromObj(interp, canvas, objv[4], &y) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[5], &angle) != TCL_OK) { result = TCL_ERROR; goto done; } angle = angle * 3.1415927 / 180.0; FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { EventuallyRedrawItem(canvasPtr, itemPtr); ItemRotate(canvasPtr, itemPtr, x, y, angle); EventuallyRedrawItem(canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } break; } case CANV_SCALE: { double xOrigin, yOrigin, xScale, yScale; if (objc != 7) { Tcl_WrongNumArgs(interp, 2, objv, |
︙ | ︙ |
Changes to generic/tkEntry.c.
︙ | ︙ | |||
3215 3216 3217 3218 3219 3220 3221 | */ /* ARGSUSED */ static char * EntryTextVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ | | | < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > | | 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 | */ /* ARGSUSED */ static char * EntryTextVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ const char *name1, /* Not used. */ const char *name2, /* Not used. */ int flags) /* Information about what happened. */ { Entry *entryPtr = clientData; const char *value; if (entryPtr->flags & ENTRY_DELETED) { /* * Just abort early if we entered here while being deleted. */ return NULL; } /* * If the variable is unset, then immediately recreate it unless the whole * interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && entryPtr->textVarName) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, EntryTextVarProc, probe); if (probe == (ClientData)entryPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * textVarName, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_SetVar2(interp, entryPtr->textVarName, NULL, entryPtr->string, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, EntryTextVarProc, clientData); entryPtr->flags |= ENTRY_VAR_TRACED; } return 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). |
︙ | ︙ |
Added generic/tkImgSVGnano.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | /* * tkImgSVGnano.c * * A photo file handler for SVG files. * * Copyright (c) 2013-14 Mikko Mononen [email protected] * Copyright (c) 2018 Christian Gollwitzer [email protected] * Copyright (c) 2018 Rene Zaumseil [email protected] * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * * This handler is build using the original nanosvg library files from * https://github.com/memononen/nanosvg and the tcl extension files from * https://github.com/auriocus/tksvg * */ #include "tkInt.h" #define NANOSVG_malloc ckalloc #define NANOSVG_realloc ckrealloc #define NANOSVG_free ckfree #define NANOSVG_SCOPE MODULE_SCOPE #define NANOSVG_ALL_COLOR_KEYWORDS #define NANOSVG_IMPLEMENTATION #include "nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION #include "nanosvgrast.h" /* Additional parameters to nsvgRasterize() */ typedef struct { double x; double y; double scale; } RastOpts; /* * Per interp cache of last NSVGimage which was matched to * be immediately rasterized after the match. This helps to * eliminate double parsing of the SVG file/string. */ typedef struct { ClientData dataOrChan; Tcl_DString formatString; NSVGimage *nsvgImage; RastOpts ropts; } NSVGcache; static int FileMatchSVG(Tcl_Channel chan, const char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp); static int FileReadSVG(Tcl_Interp *interp, Tcl_Channel chan, const char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY); static int StringMatchSVG(Tcl_Obj *dataObj, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp); static int StringReadSVG(Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY); static NSVGimage * ParseSVGWithOptions(Tcl_Interp *interp, const char *input, int length, Tcl_Obj *format, RastOpts *ropts); static int RasterizeSVG(Tcl_Interp *interp, Tk_PhotoHandle imageHandle, NSVGimage *nsvgImage, int destX, int destY, int width, int height, int srcX, int srcY, RastOpts *ropts); static NSVGcache * GetCachePtr(Tcl_Interp *interp); static int CacheSVG(Tcl_Interp *interp, ClientData dataOrChan, Tcl_Obj *formatObj, NSVGimage *nsvgImage, RastOpts *ropts); static NSVGimage * GetCachedSVG(Tcl_Interp *interp, ClientData dataOrChan, Tcl_Obj *formatObj, RastOpts *ropts); static void CleanCache(Tcl_Interp *interp); static void FreeCache(ClientData clientData, Tcl_Interp *interp); /* * The format record for the SVG nano file format: */ Tk_PhotoImageFormat tkImgFmtSVGnano = { "svg", /* name */ FileMatchSVG, /* fileMatchProc */ StringMatchSVG, /* stringMatchProc */ FileReadSVG, /* fileReadProc */ StringReadSVG, /* stringReadProc */ NULL, /* fileWriteProc */ NULL, /* stringWriteProc */ NULL }; /* *---------------------------------------------------------------------- * * FileMatchSVG -- * * This function is invoked by the photo image type to see if a file * contains image data in SVG format. * * Results: * The return value is >0 if the file can be successfully parsed, * and 0 otherwise. * * Side effects: * The file is saved in the internal cache for further use. * *---------------------------------------------------------------------- */ static int FileMatchSVG( Tcl_Channel chan, const char *fileName, Tcl_Obj *formatObj, int *widthPtr, int *heightPtr, Tcl_Interp *interp) { int length; Tcl_Obj *dataObj = Tcl_NewObj(); const char *data; RastOpts ropts; NSVGimage *nsvgImage; CleanCache(interp); if (Tcl_ReadChars(chan, dataObj, -1, 0) == -1) { /* in case of an error reading the file */ Tcl_DecrRefCount(dataObj); return 0; } data = Tcl_GetStringFromObj(dataObj, &length); nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); Tcl_DecrRefCount(dataObj); if (nsvgImage != NULL) { *widthPtr = (int) ceil(nsvgImage->width * ropts.scale); *heightPtr = (int) ceil(nsvgImage->height * ropts.scale); if ((*widthPtr <= 0) || (*heightPtr <= 0)) { nsvgDelete(nsvgImage); return 0; } if (!CacheSVG(interp, chan, formatObj, nsvgImage, &ropts)) { nsvgDelete(nsvgImage); } return 1; } return 0; } /* *---------------------------------------------------------------------- * * FileReadSVG -- * * This function is called by the photo image type to read SVG 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 the interp's result. * * Side effects: * The access position in file f is changed, and new data is added to the * image given by imageHandle. * *---------------------------------------------------------------------- */ static int FileReadSVG( Tcl_Interp *interp, Tcl_Channel chan, const char *fileName, Tcl_Obj *formatObj, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY) { int length; const char *data; RastOpts ropts; NSVGimage *nsvgImage = GetCachedSVG(interp, chan, formatObj, &ropts); if (nsvgImage == NULL) { Tcl_Obj *dataObj = Tcl_NewObj(); if (Tcl_ReadChars(chan, dataObj, -1, 0) == -1) { /* in case of an error reading the file */ Tcl_DecrRefCount(dataObj); Tcl_SetObjResult(interp, Tcl_NewStringObj("read error", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "READ_ERROR", NULL); return TCL_ERROR; } data = Tcl_GetStringFromObj(dataObj, &length); nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); Tcl_DecrRefCount(dataObj); if (nsvgImage == NULL) { return TCL_ERROR; } } return RasterizeSVG(interp, imageHandle, nsvgImage, destX, destY, width, height, srcX, srcY, &ropts); } /* *---------------------------------------------------------------------- * * StringMatchSVG -- * * This function is invoked by the photo image type to see if a string * contains image data in SVG format. * * Results: * The return value is >0 if the file can be successfully parsed, * and 0 otherwise. * * Side effects: * The file is saved in the internal cache for further use. * *---------------------------------------------------------------------- */ static int StringMatchSVG( Tcl_Obj *dataObj, Tcl_Obj *formatObj, int *widthPtr, int *heightPtr, Tcl_Interp *interp) { int length; const char *data; RastOpts ropts; NSVGimage *nsvgImage; CleanCache(interp); data = Tcl_GetStringFromObj(dataObj, &length); nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); if (nsvgImage != NULL) { *widthPtr = (int) ceil(nsvgImage->width * ropts.scale); *heightPtr = (int) ceil(nsvgImage->height * ropts.scale); if ((*widthPtr <= 0) || (*heightPtr <= 0)) { nsvgDelete(nsvgImage); return 0; } if (!CacheSVG(interp, dataObj, formatObj, nsvgImage, &ropts)) { nsvgDelete(nsvgImage); } return 1; } return 0; } /* *---------------------------------------------------------------------- * * StringReadSVG -- * * This function is called by the photo image type to read SVG format * data from a string 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 the interp's result. * * Side effects: * New data is added to the image given by imageHandle. * *---------------------------------------------------------------------- */ static int StringReadSVG( Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *formatObj, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY) { int length; const char *data; RastOpts ropts; NSVGimage *nsvgImage = GetCachedSVG(interp, dataObj, formatObj, &ropts); if (nsvgImage == NULL) { data = Tcl_GetStringFromObj(dataObj, &length); nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); } if (nsvgImage == NULL) { return TCL_ERROR; } return RasterizeSVG(interp, imageHandle, nsvgImage, destX, destY, width, height, srcX, srcY, &ropts); } /* *---------------------------------------------------------------------- * * ParseSVGWithOptions -- * * This function is called to parse the given input string as SVG. * * Results: * Return a newly create NSVGimage on success, and NULL otherwise. * * Side effects: * *---------------------------------------------------------------------- */ static NSVGimage * ParseSVGWithOptions( Tcl_Interp *interp, const char *input, int length, Tcl_Obj *formatObj, RastOpts *ropts) { Tcl_Obj **objv = NULL; int objc = 0; double dpi = 96.0; char unit[3], *p; char *inputCopy = NULL; NSVGimage *nsvgImage; static const char *const fmtOptions[] = { "-dpi", "-scale", "-unit", NULL }; enum fmtOptions { OPT_DPI, OPT_SCALE, OPT_UNIT }; /* * The parser destroys the original input string, * therefore first duplicate. */ inputCopy = attemptckalloc(length+1); if (inputCopy == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc data buffer", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL); goto error; } memcpy(inputCopy, input, length); inputCopy[length] = '\0'; /* * Process elements of format specification as a list. */ strcpy(unit, "px"); ropts->x = ropts->y = 0.0; ropts->scale = 1.0; if ((formatObj != NULL) && Tcl_ListObjGetElements(interp, formatObj, &objc, &objv) != TCL_OK) { goto error; } for (; objc > 0 ; objc--, objv++) { int optIndex; /* * Ignore the "svg" part of the format specification. */ if (!strcasecmp(Tcl_GetString(objv[0]), "svg")) { continue; } if (Tcl_GetIndexFromObjStruct(interp, objv[0], fmtOptions, sizeof(char *), "option", 0, &optIndex) == TCL_ERROR) { goto error; } if (objc < 2) { ckfree(inputCopy); inputCopy = NULL; Tcl_WrongNumArgs(interp, 1, objv, "value"); goto error; } objc--; objv++; switch ((enum fmtOptions) optIndex) { case OPT_DPI: if (Tcl_GetDoubleFromObj(interp, objv[0], &dpi) == TCL_ERROR) { goto error; } if (dpi < 0.0) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "-dpi value must be positive", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_DPI", NULL); goto error; } break; case OPT_SCALE: if (Tcl_GetDoubleFromObj(interp, objv[0], &ropts->scale) == TCL_ERROR) { goto error; } if (ropts->scale <= 0.0) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "-scale value must be positive", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE", NULL); goto error; } break; case OPT_UNIT: p = Tcl_GetString(objv[0]); if ((p != NULL) && (p[0])) { strncpy(unit, p, 3); unit[2] = '\0'; } break; } } nsvgImage = nsvgParse(inputCopy, unit, (float) dpi); if (nsvgImage == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot parse SVG image", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "PARSE_ERROR", NULL); goto error; } ckfree(inputCopy); return nsvgImage; error: if (inputCopy != NULL) { ckfree(inputCopy); } return NULL; } /* *---------------------------------------------------------------------- * * RasterizeSVG -- * * This function is called to rasterize the given nsvgImage and * fill the imageHandle with data. * * Results: * A standard TCL completion code. If TCL_ERROR is returned then an error * message is left in the interp's result. * * * Side effects: * On error the given nsvgImage will be deleted. * *---------------------------------------------------------------------- */ static int RasterizeSVG( Tcl_Interp *interp, Tk_PhotoHandle imageHandle, NSVGimage *nsvgImage, int destX, int destY, int width, int height, int srcX, int srcY, RastOpts *ropts) { int w, h, c; NSVGrasterizer *rast; unsigned char *imgData; Tk_PhotoImageBlock svgblock; w = (int) ceil(nsvgImage->width * ropts->scale); h = (int) ceil(nsvgImage->height * ropts->scale); rast = nsvgCreateRasterizer(); if (rast == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot initialize rasterizer", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "RASTERIZER_ERROR", NULL); goto cleanAST; } imgData = attemptckalloc(w * h *4); if (imgData == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc image buffer", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL); goto cleanRAST; } nsvgRasterize(rast, nsvgImage, (float) ropts->x, (float) ropts->y, (float) ropts->scale, imgData, w, h, w * 4); /* transfer the data to a photo block */ svgblock.pixelPtr = imgData; svgblock.width = w; svgblock.height = h; svgblock.pitch = w * 4; svgblock.pixelSize = 4; for (c = 0; c <= 3; c++) { svgblock.offset[c] = c; } if (Tk_PhotoExpand(interp, imageHandle, destX + width, destY + height) != TCL_OK) { goto cleanRAST; } if (Tk_PhotoPutBlock(interp, imageHandle, &svgblock, destX, destY, width, height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) { goto cleanimg; } ckfree(imgData); nsvgDeleteRasterizer(rast); nsvgDelete(nsvgImage); return TCL_OK; cleanimg: ckfree(imgData); cleanRAST: nsvgDeleteRasterizer(rast); cleanAST: nsvgDelete(nsvgImage); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * GetCachePtr -- * * This function is called to get the per interpreter used * svg image cache. * * Results: * Return a pointer to the used cache. * * Side effects: * Initialize the cache on the first call. * *---------------------------------------------------------------------- */ static NSVGcache * GetCachePtr( Tcl_Interp *interp ) { NSVGcache *cachePtr = Tcl_GetAssocData(interp, "tksvgnano", NULL); if (cachePtr == NULL) { cachePtr = ckalloc(sizeof(NSVGcache)); cachePtr->dataOrChan = NULL; Tcl_DStringInit(&cachePtr->formatString); cachePtr->nsvgImage = NULL; Tcl_SetAssocData(interp, "tksvgnano", FreeCache, cachePtr); } return cachePtr; } /* *---------------------------------------------------------------------- * * CacheSVG -- * * Add the given svg image informations to the cache for further usage. * * Results: * Return 1 on success, and 0 otherwise. * * Side effects: * *---------------------------------------------------------------------- */ static int CacheSVG( Tcl_Interp *interp, ClientData dataOrChan, Tcl_Obj *formatObj, NSVGimage *nsvgImage, RastOpts *ropts) { int length; const char *data; NSVGcache *cachePtr = GetCachePtr(interp); if (cachePtr != NULL) { cachePtr->dataOrChan = dataOrChan; if (formatObj != NULL) { data = Tcl_GetStringFromObj(formatObj, &length); Tcl_DStringAppend(&cachePtr->formatString, data, length); } cachePtr->nsvgImage = nsvgImage; cachePtr->ropts = *ropts; return 1; } return 0; } /* *---------------------------------------------------------------------- * * GetCachedSVG -- * * Try to get the NSVGimage from the internal cache. * * Results: * Return the found NSVGimage on success, and NULL otherwise. * * Side effects: * Calls the CleanCache() function. * *---------------------------------------------------------------------- */ static NSVGimage * GetCachedSVG( Tcl_Interp *interp, ClientData dataOrChan, Tcl_Obj *formatObj, RastOpts *ropts) { int length; const char *data; NSVGcache *cachePtr = GetCachePtr(interp); NSVGimage *nsvgImage = NULL; if ((cachePtr != NULL) && (cachePtr->nsvgImage != NULL) && (cachePtr->dataOrChan == dataOrChan)) { if (formatObj != NULL) { data = Tcl_GetStringFromObj(formatObj, &length); if (strcmp(data, Tcl_DStringValue(&cachePtr->formatString)) == 0) { nsvgImage = cachePtr->nsvgImage; *ropts = cachePtr->ropts; cachePtr->nsvgImage = NULL; } } else if (Tcl_DStringLength(&cachePtr->formatString) == 0) { nsvgImage = cachePtr->nsvgImage; *ropts = cachePtr->ropts; cachePtr->nsvgImage = NULL; } } CleanCache(interp); return nsvgImage; } /* *---------------------------------------------------------------------- * * CleanCache -- * * Reset the cache and delete the saved image in it. * * Results: * * Side effects: * *---------------------------------------------------------------------- */ static void CleanCache(Tcl_Interp *interp) { NSVGcache *cachePtr = GetCachePtr(interp); if (cachePtr != NULL) { cachePtr->dataOrChan = NULL; Tcl_DStringSetLength(&cachePtr->formatString, 0); if (cachePtr->nsvgImage != NULL) { nsvgDelete(cachePtr->nsvgImage); cachePtr->nsvgImage = NULL; } } } /* *---------------------------------------------------------------------- * * FreeCache -- * * This function is called to clean up the internal cache data. * * Results: * * Side effects: * Existing image data in the cache and the cache will be deleted. * *---------------------------------------------------------------------- */ static void FreeCache(ClientData clientData, Tcl_Interp *interp) { NSVGcache *cachePtr = clientData; Tcl_DStringFree(&cachePtr->formatString); if (cachePtr->nsvgImage != NULL) { nsvgDelete(cachePtr->nsvgImage); } ckfree(cachePtr); } |
Changes to generic/tkInt.h.
︙ | ︙ | |||
982 983 984 985 986 987 988 989 990 991 992 993 994 995 | MODULE_SCOPE const Tk_SmoothMethod tkBezierSmoothMethod; MODULE_SCOPE Tk_ImageType tkBitmapImageType; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtGIF; MODULE_SCOPE void (*tkHandleEventProc) (XEvent* eventPtr); MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtDefault; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtPNG; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtPPM; MODULE_SCOPE TkMainInfo *tkMainWindowList; MODULE_SCOPE Tk_ImageType tkPhotoImageType; MODULE_SCOPE Tcl_HashTable tkPredefBitmapTable; MODULE_SCOPE const char *const tkWebColors[20]; /* | > | 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 | MODULE_SCOPE const Tk_SmoothMethod tkBezierSmoothMethod; MODULE_SCOPE Tk_ImageType tkBitmapImageType; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtGIF; MODULE_SCOPE void (*tkHandleEventProc) (XEvent* eventPtr); MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtDefault; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtPNG; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtPPM; MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtSVGnano; MODULE_SCOPE TkMainInfo *tkMainWindowList; MODULE_SCOPE Tk_ImageType tkPhotoImageType; MODULE_SCOPE Tcl_HashTable tkPredefBitmapTable; MODULE_SCOPE const char *const tkWebColors[20]; /* |
︙ | ︙ | |||
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | MODULE_SCOPE Tcl_Command TkMakeEnsemble(Tcl_Interp *interp, const char *nsname, const char *name, ClientData clientData, const TkEnsemble *map); MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); MODULE_SCOPE void TkpCancelWarp(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, int toplevel, Tcl_Obj *nameObj); #ifdef _WIN32 #define TkParseColor XParseColor #else MODULE_SCOPE Status TkParseColor (Display * display, Colormap map, const char* spec, XColor * colorPtr); | > > > > > | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 | MODULE_SCOPE Tcl_Command TkMakeEnsemble(Tcl_Interp *interp, const char *nsname, const char *name, ClientData clientData, const TkEnsemble *map); MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE void TkInitEmbeddedConfigurationInformation( Tcl_Interp *interp); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); MODULE_SCOPE void TkpCancelWarp(TkDisplay *dispPtr); MODULE_SCOPE int TkListCreateFrame(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *listObj, int toplevel, Tcl_Obj *nameObj); MODULE_SCOPE void TkRotatePoint(double originX, double originY, double sine, double cosine, double *xPtr, double *yPtr); #ifdef _WIN32 #define TkParseColor XParseColor #else MODULE_SCOPE Status TkParseColor (Display * display, Colormap map, const char* spec, XColor * colorPtr); |
︙ | ︙ |
Changes to generic/tkListbox.c.
︙ | ︙ | |||
3433 3434 3435 3436 3437 3438 3439 | *---------------------------------------------------------------------- */ static char * ListboxListVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ | | | < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > | 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 | *---------------------------------------------------------------------- */ static char * ListboxListVarProc( ClientData clientData, /* Information about button. */ Tcl_Interp *interp, /* Interpreter containing variable. */ const char *name1, /* Not used. */ const char *name2, /* Not used. */ int flags) /* Information about what happened. */ { Listbox *listPtr = clientData; Tcl_Obj *oldListObj, *varListObj; int oldLength, i; Tcl_HashEntry *entry; /* * Bwah hahahaha! Puny mortal, you can't unset a -listvar'd variable! */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && listPtr->listVarName) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, listPtr->listVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ListboxListVarProc, probe); if (probe == (ClientData)listPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * listVarName, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_SetVar2Ex(interp, listPtr->listVarName, NULL, listPtr->listObj, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, listPtr->listVarName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ListboxListVarProc, clientData); return NULL; } |
︙ | ︙ |
Changes to generic/tkMenu.c.
︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 | int flags) /* Describes what just happened. */ { TkMenuEntry *mePtr = clientData; TkMenu *menuPtr; const char *value; const char *name, *onValue; | | | > < < < < < < < < < < < > | > | | | > > | > > > > > > > > > > > > > | 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 | int flags) /* Describes what just happened. */ { TkMenuEntry *mePtr = clientData; TkMenu *menuPtr; const char *value; const char *name, *onValue; if (Tcl_InterpDeleted(interp) || (mePtr->namePtr == NULL)) { /* * Do nothing if the interpreter is going away or we have * no variable name. */ return NULL; } menuPtr = mePtr->menuPtr; if (menuPtr->menuFlags & MENU_DELETION_PENDING) { return NULL; } name = Tcl_GetString(mePtr->namePtr); /* * If the variable is being unset, then re-establish the trace. */ if (flags & TCL_TRACE_UNSETS) { ClientData probe = NULL; mePtr->entryFlags &= ~ENTRY_SELECTED; do { probe = Tcl_VarTraceInfo(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, probe); if (probe == (ClientData)mePtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * namePtr, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_TraceVar2(interp, name, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, clientData); TkpConfigureMenuEntry(mePtr); TkEventuallyRedrawMenu(menuPtr, NULL); return NULL; } /* * Use the value of the variable to update the selected status of the menu |
︙ | ︙ |
Changes to generic/tkMenuDraw.c.
︙ | ︙ | |||
471 472 473 474 475 476 477 | * Arrange for an entry of a menu, or the whole menu, to be redisplayed * at some point in the future. * * Results: * None. * * Side effects: | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | * 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 handler is scheduled to do the redisplay, if there isn't * one already scheduled. * *---------------------------------------------------------------------- */ void TkEventuallyRedrawMenu( |
︙ | ︙ |
Changes to generic/tkMenubutton.c.
︙ | ︙ | |||
877 878 879 880 881 882 883 | const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register TkMenuButton *mbPtr = clientData; const char *value; unsigned len; | < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register TkMenuButton *mbPtr = clientData; const char *value; unsigned len; /* * If the variable is unset, then immediately recreate it unless the whole * interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && mbPtr->textVarName) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuButtonTextVarProc, probe); if (probe == (ClientData)mbPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * textVarName, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_SetVar2(interp, mbPtr->textVarName, NULL, mbPtr->text, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, mbPtr->textVarName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuButtonTextVarProc, clientData); } return NULL; |
︙ | ︙ |
Changes to generic/tkMessage.c.
︙ | ︙ | |||
834 835 836 837 838 839 840 | const char *name1, /* Name of variable. */ const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register Message *msgPtr = clientData; const char *value; | < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | const char *name1, /* Name of variable. */ const char *name2, /* Second part of variable name. */ int flags) /* Information about what happened. */ { register Message *msgPtr = clientData; const char *value; /* * If the variable is unset, then immediately recreate it unless the whole * interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && msgPtr->textVarName) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MessageTextVarProc, probe); if (probe == (ClientData)msgPtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * textVarName, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_SetVar2(interp, msgPtr->textVarName, NULL, msgPtr->string, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, msgPtr->textVarName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MessageTextVarProc, clientData); } return NULL; |
︙ | ︙ |
Added generic/tkPkgConfig.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | /* * tkPkgConfig.c -- * * This file contains the configuration information to embed into the tcl * binary library. * * Copyright (c) 2002 Andreas Kupries <[email protected]> * Copyright (c) 2017 Stuart Cassoff <[email protected]> * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ /* Note, the definitions in this module are influenced by the following C * preprocessor macros: * * OSCMa = shortcut for "old style configuration macro activates" * NSCMdt = shortcut for "new style configuration macro declares that" * * - TCL_THREADS OSCMa compilation as threaded. * - TCL_MEM_DEBUG OSCMa memory debugging. * * - TCL_CFG_DO64BIT NSCMdt tk is compiled for a 64bit system. * - NDEBUG NSCMdt tk is compiled with symbol info off. * - TCL_CFG_OPTIMIZED NSCMdt tk is compiled with cc optimizations on * - TCL_CFG_PROFILED NSCMdt tk is compiled with profiling info. * * - _WIN32 || __CYGWIN__ The value for the fontsytem key will be * MAC_OSX_TK chosen based on these macros/defines. * HAVE_XFT NSCMdt xft font support was requested. * * - CFG_RUNTIME_* Paths to various stuff at runtime. * - CFG_INSTALL_* Paths to various stuff at installation time. * * - TCL_CFGVAL_ENCODING string containing the encoding used for the * configuration values. */ #include "tkInt.h" #ifndef TCL_CFGVAL_ENCODING #define TCL_CFGVAL_ENCODING "ascii" #endif /* * Use C preprocessor statements to define the various values for the embedded * configuration information. */ #ifdef TCL_THREADS # define CFG_THREADED "1" #else # define CFG_THREADED "0" #endif #ifdef TCL_MEM_DEBUG # define CFG_MEMDEBUG "1" #else # define CFG_MEMDEBUG "0" #endif #ifdef TCL_CFG_DO64BIT # define CFG_64 "1" #else # define CFG_64 "0" #endif #ifndef NDEBUG # define CFG_DEBUG "1" #else # define CFG_DEBUG "0" #endif #ifdef TCL_CFG_OPTIMIZED # define CFG_OPTIMIZED "1" #else # define CFG_OPTIMIZED "0" #endif #ifdef TCL_CFG_PROFILED # define CFG_PROFILED "1" #else # define CFG_PROFILED "0" #endif #if defined(_WIN32) || defined(__CYGWIN__) # define CFG_FONTSYSTEM "gdi" #elif defined(MAC_OSX_TK) # define CFG_FONTSYSTEM "cocoa" #elif defined(HAVE_XFT) # define CFG_FONTSYSTEM "xft" #else # define CFG_FONTSYSTEM "x11" #endif static Tcl_Config const cfg[] = { {"debug", CFG_DEBUG}, {"threaded", CFG_THREADED}, {"profiled", CFG_PROFILED}, {"64bit", CFG_64}, {"optimized", CFG_OPTIMIZED}, {"mem_debug", CFG_MEMDEBUG}, {"fontsystem", CFG_FONTSYSTEM}, /* Runtime paths to various stuff */ #ifdef CFG_RUNTIME_LIBDIR {"libdir,runtime", CFG_RUNTIME_LIBDIR}, #endif #ifdef CFG_RUNTIME_BINDIR {"bindir,runtime", CFG_RUNTIME_BINDIR}, #endif #ifdef CFG_RUNTIME_SCRDIR {"scriptdir,runtime", CFG_RUNTIME_SCRDIR}, #endif #ifdef CFG_RUNTIME_INCDIR {"includedir,runtime", CFG_RUNTIME_INCDIR}, #endif #ifdef CFG_RUNTIME_DOCDIR {"docdir,runtime", CFG_RUNTIME_DOCDIR}, #endif #ifdef CFG_RUNTIME_DEMODIR {"demodir,runtime", CFG_RUNTIME_DEMODIR}, #endif /* Installation paths to various stuff */ #ifdef CFG_INSTALL_LIBDIR {"libdir,install", CFG_INSTALL_LIBDIR}, #endif #ifdef CFG_INSTALL_BINDIR {"bindir,install", CFG_INSTALL_BINDIR}, #endif #ifdef CFG_INSTALL_SCRDIR {"scriptdir,install", CFG_INSTALL_SCRDIR}, #endif #ifdef CFG_INSTALL_INCDIR {"includedir,install", CFG_INSTALL_INCDIR}, #endif #ifdef CFG_INSTALL_DOCDIR {"docdir,install", CFG_INSTALL_DOCDIR}, #endif #ifdef CFG_INSTALL_DEMODIR {"demodir,install", CFG_INSTALL_DEMODIR}, #endif /* Last entry, closes the array */ {NULL, NULL} }; void TkInitEmbeddedConfigurationInformation( Tcl_Interp *interp) /* Interpreter the configuration command is * registered in. */ { Tcl_RegisterConfig(interp, "tk", cfg, TCL_CFGVAL_ENCODING); } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tkPlace.c.
︙ | ︙ | |||
691 692 693 694 695 696 697 | if (slavePtr->tkwin == tkwin) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't place %s relative to itself", Tk_PathName(slavePtr->tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "LOOP", NULL); goto error; } | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | if (slavePtr->tkwin == tkwin) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't place %s relative to itself", Tk_PathName(slavePtr->tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "LOOP", NULL); goto error; } /* * Check for management loops. */ for (master = (TkWindow *)tkwin; master != NULL; master = (TkWindow *)TkGetGeomMaster(master)) { if (master == (TkWindow *)slavePtr->tkwin) { |
︙ | ︙ |
Changes to generic/tkRectOval.c.
︙ | ︙ | |||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 | Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static int RectOvalToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static int RectToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *areaPtr); static double RectToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static void ScaleRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* | > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static int RectOvalToPostscript(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); static int RectToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *areaPtr); static double RectToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr); static void RotateRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double angleRad); static void ScaleRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY); static void TranslateRectOval(Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY); /* |
︙ | ︙ | |||
176 177 178 179 180 181 182 | TranslateRectOval, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | TranslateRectOval, /* translateProc */ NULL, /* indexProc */ NULL, /* icursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateRectOval, /* rotateProc */ 0, NULL, NULL }; Tk_ItemType tkOvalType = { "oval", /* name */ sizeof(RectOvalItem), /* itemSize */ CreateRectOval, /* createProc */ configSpecs, /* configSpecs */ |
︙ | ︙ | |||
200 201 202 203 204 205 206 | TranslateRectOval, /* translateProc */ NULL, /* indexProc */ NULL, /* cursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ | > | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | TranslateRectOval, /* translateProc */ NULL, /* indexProc */ NULL, /* cursorProc */ NULL, /* selectionProc */ NULL, /* insertProc */ NULL, /* dTextProc */ NULL, /* nextPtr */ RotateRectOval, /* rotateProc */ 0, NULL, NULL }; /* *-------------------------------------------------------------- * * CreateRectOval -- * |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | && ((xDelta2 + yDelta1) < 1.0) && ((xDelta2 + yDelta2) < 1.0)) { return -1; } } return result; } /* *-------------------------------------------------------------- * * ScaleRectOval -- * * This function is invoked to rescale a rectangle or oval item. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | && ((xDelta2 + yDelta1) < 1.0) && ((xDelta2 + yDelta2) < 1.0)) { return -1; } } return result; } /* *-------------------------------------------------------------- * * RotateRectOval -- * * This function is invoked to rotate a rectangle or oval item's * coordinates. It works by rotating a computed point in the centre of * the bounding box, NOT by rotating the corners of the bounding box. * * Results: * None. * * Side effects: * The position of the rectangle or oval is rotated by angleRad about * (originX, originY), and the bounding box is updated in the generic * part of the item structure. * *-------------------------------------------------------------- */ static void RotateRectOval( Tk_Canvas canvas, /* Canvas containing rectangle. */ Tk_Item *itemPtr, /* Rectangle to be scaled. */ double originX, double originY, /* Origin about which to rotate rect. */ double angleRad) /* Amount to scale in X direction. */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; double newX, newY, oldX, oldY; /* * Compute the centre of the box, then rotate that about the origin. */ newX = oldX = (rectOvalPtr->bbox[0] + rectOvalPtr->bbox[2]) / 2.0; newY = oldY = (rectOvalPtr->bbox[1] + rectOvalPtr->bbox[3]) / 2.0; TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad), &newX, &newY); /* * Apply the translation to the box. */ rectOvalPtr->bbox[0] += newX - oldX; rectOvalPtr->bbox[1] += newY - oldY; rectOvalPtr->bbox[2] += newX - oldX; rectOvalPtr->bbox[3] += newY - oldY; ComputeRectOvalBbox(canvas, rectOvalPtr); } /* *-------------------------------------------------------------- * * ScaleRectOval -- * * This function is invoked to rescale a rectangle or oval item. |
︙ | ︙ |
Changes to generic/tkScale.c.
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 | { register TkScale *scalePtr = clientData; const char *resultStr; double value; Tcl_Obj *valuePtr; int result; | < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > | 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 | { register TkScale *scalePtr = clientData; const char *resultStr; double value; Tcl_Obj *valuePtr; int result; /* * If the variable is unset, then immediately recreate it unless the whole * interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (!Tcl_InterpDeleted(interp) && scalePtr->varNamePtr) { ClientData probe = NULL; do { probe = Tcl_VarTraceInfo(interp, Tcl_GetString(scalePtr->varNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, probe); if (probe == (ClientData)scalePtr) { break; } } while (probe); if (probe) { /* * We were able to fetch the unset trace for our * varNamePtr, which means it is not unset and not * the cause of this unset trace. Instead some outdated * former variable must be, and we should ignore it. */ return NULL; } Tcl_TraceVar2(interp, Tcl_GetString(scalePtr->varNamePtr), NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, clientData); scalePtr->flags |= NEVER_SET; TkScaleSetValue(scalePtr, scalePtr->value, 1, 0); } return NULL; |
︙ | ︙ |
Changes to generic/tkText.c.
︙ | ︙ | |||
2776 2777 2778 2779 2780 2781 2782 | const TkTextIndex *index2Ptr) /* Index describing second location. */ { TkUndoSubAtom *iAtom, *dAtom; int canUndo, canRedo; char lMarkName[20] = "tk::undoMarkL"; char rMarkName[20] = "tk::undoMarkR"; | | | 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 | const TkTextIndex *index2Ptr) /* Index describing second location. */ { TkUndoSubAtom *iAtom, *dAtom; int canUndo, canRedo; char lMarkName[20] = "tk::undoMarkL"; char rMarkName[20] = "tk::undoMarkR"; char stringUndoMarkId[16] = ""; /* * Create the helpers. */ Tcl_Obj *seeInsertObj = Tcl_NewObj(); Tcl_Obj *markSet1InsertObj = Tcl_NewObj(); |
︙ | ︙ |
Changes to generic/tkWindow.c.
︙ | ︙ | |||
336 337 338 339 340 341 342 343 344 345 346 347 348 349 | * Create built-in photo image formats. */ Tk_CreatePhotoImageFormat(&tkImgFmtDefault); Tk_CreatePhotoImageFormat(&tkImgFmtGIF); Tk_CreatePhotoImageFormat(&tkImgFmtPNG); Tk_CreatePhotoImageFormat(&tkImgFmtPPM); } if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) { dispPtr = ((TkWindow *) parent)->dispPtr; screenId = Tk_ScreenNumber(parent); } else { dispPtr = GetScreen(interp, screenName, &screenId); | > | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | * Create built-in photo image formats. */ Tk_CreatePhotoImageFormat(&tkImgFmtDefault); Tk_CreatePhotoImageFormat(&tkImgFmtGIF); Tk_CreatePhotoImageFormat(&tkImgFmtPNG); Tk_CreatePhotoImageFormat(&tkImgFmtPPM); Tk_CreatePhotoImageFormat(&tkImgFmtSVGnano); } if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) { dispPtr = ((TkWindow *) parent)->dispPtr; screenId = Tk_ScreenNumber(parent); } else { dispPtr = GetScreen(interp, screenName, &screenId); |
︙ | ︙ | |||
3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 | * Ensure that we are getting a compatible version of Tcl. */ if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } /* * Ensure that our obj-types are registered with the Tcl runtime. */ TkRegisterObjTypes(); tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); | > > > > > > | 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 | * Ensure that we are getting a compatible version of Tcl. */ if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } /* * TIP #59: Make embedded configuration information available. */ TkInitEmbeddedConfigurationInformation(interp); /* * Ensure that our obj-types are registered with the Tcl runtime. */ TkRegisterObjTypes(); tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
︙ | ︙ |
Changes to generic/ttk/ttkEntry.c.
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 | static int EntryConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Entry *entryPtr = recordPtr; Tcl_Obj *textVarName = entryPtr->entry.textVariableObj; Ttk_TraceHandle *vt = 0; if (mask & TEXTVAR_CHANGED) { | | | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | static int EntryConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Entry *entryPtr = recordPtr; Tcl_Obj *textVarName = entryPtr->entry.textVariableObj; Ttk_TraceHandle *vt = 0; if (mask & TEXTVAR_CHANGED) { if (textVarName && *Tcl_GetString(textVarName) != '\0') { vt = Ttk_TraceVariable(interp, textVarName,EntryTextVariableTrace,entryPtr); if (!vt) return TCL_ERROR; } } if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) { |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 | if (x > maxWidth) { x = maxWidth; roundUp = 1; } *indexPtr = Tk_PointToChar(entryPtr->entry.textLayout, x - entryPtr->entry.layoutX, 0); if (*indexPtr < entryPtr->entry.xscroll.first) { *indexPtr = entryPtr->entry.xscroll.first; } /* * Special trick: if the x-position was off-screen to the right, * round the index up to refer to the character just after the | > | 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 | if (x > maxWidth) { x = maxWidth; roundUp = 1; } *indexPtr = Tk_PointToChar(entryPtr->entry.textLayout, x - entryPtr->entry.layoutX, 0); TtkUpdateScrollInfo(entryPtr->entry.xscrollHandle); if (*indexPtr < entryPtr->entry.xscroll.first) { *indexPtr = entryPtr->entry.xscroll.first; } /* * Special trick: if the x-position was off-screen to the right, * round the index up to refer to the character just after the |
︙ | ︙ | |||
1693 1694 1695 1696 1697 1698 1699 | { Entry *entryPtr = recordPtr; if (objc == 3) { int newFirst; if (EntryIndex(interp, entryPtr, objv[2], &newFirst) != TCL_OK) { return TCL_ERROR; } | | | 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 | { Entry *entryPtr = recordPtr; if (objc == 3) { int newFirst; if (EntryIndex(interp, entryPtr, objv[2], &newFirst) != TCL_OK) { return TCL_ERROR; } TtkScrollTo(entryPtr->entry.xscrollHandle, newFirst, 1); return TCL_OK; } return TtkScrollviewCommand(interp, objc, objv, entryPtr->entry.xscrollHandle); } static const Ttk_Ensemble EntryCommands[] = { { "bbox", EntryBBoxCommand,0 }, |
︙ | ︙ |
Changes to generic/ttk/ttkScroll.c.
︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | * -yscrollcommand has changed). */ void TtkScrollbarUpdateRequired(ScrollHandle h) { h->flags |= SCROLL_UPDATE_REQUIRED; } /* TtkScrollviewCommand -- * Widget [xy]view command implementation. * * $w [xy]view -- return current view region * $w [xy]view $index -- set topmost item * $w [xy]view moveto $fraction * $w [xy]view scroll $number $what -- scrollbar interface */ int TtkScrollviewCommand( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle h) { Scrollable *s = h->scrollPtr; | > > > > > > > > > > > > > > > > | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | * -yscrollcommand has changed). */ void TtkScrollbarUpdateRequired(ScrollHandle h) { h->flags |= SCROLL_UPDATE_REQUIRED; } /* TtkUpdateScrollInfo -- * Call the layoutProc to update the scroll info first, last, and total. * Do it only if needed, that is when a redisplay is pending (which * indicates scroll info are possibly out of date). */ void TtkUpdateScrollInfo(ScrollHandle h) { if (h->corePtr->flags & REDISPLAY_PENDING) { h->corePtr->widgetSpec->layoutProc(h->corePtr); } } /* TtkScrollviewCommand -- * Widget [xy]view command implementation. * * $w [xy]view -- return current view region * $w [xy]view $index -- set topmost item * $w [xy]view moveto $fraction * $w [xy]view scroll $number $what -- scrollbar interface */ int TtkScrollviewCommand( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle h) { Scrollable *s = h->scrollPtr; int newFirst; TtkUpdateScrollInfo(h); newFirst = s->first; if (objc == 2) { Tcl_Obj *result[2]; result[0] = Tcl_NewDoubleObj((double)s->first / s->total); result[1] = Tcl_NewDoubleObj((double)s->last / s->total); Tcl_SetObjResult(interp, Tcl_NewListObj(2, result)); return TCL_OK; |
︙ | ︙ | |||
222 223 224 225 226 227 228 | int perPage = s->last - s->first; /* @@@ */ newFirst = s->first + count * perPage; break; } } } | | | > > > > | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | int perPage = s->last - s->first; /* @@@ */ newFirst = s->first + count * perPage; break; } } } TtkScrollTo(h, newFirst, 0); return TCL_OK; } void TtkScrollTo(ScrollHandle h, int newFirst, int updateScrollInfo) { Scrollable *s = h->scrollPtr; if (updateScrollInfo) { TtkUpdateScrollInfo(h); } if (newFirst >= s->total) newFirst = s->total - 1; if (newFirst > s->first && s->last >= s->total) /* don't scroll past end */ newFirst = s->first; if (newFirst < 0) newFirst = 0; |
︙ | ︙ |
Changes to generic/ttk/ttkTrace.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | /* * Tcl_VarTraceProc for trace handles. */ static char * VarTraceProc( ClientData clientData, /* Widget record pointer */ Tcl_Interp *interp, /* Interpreter containing variable. */ | | | < < < < < < < < < < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /* * Tcl_VarTraceProc for trace handles. */ static char * VarTraceProc( ClientData clientData, /* Widget record pointer */ Tcl_Interp *interp, /* Interpreter containing variable. */ const char *name1, /* (unused) */ const char *name2, /* (unused) */ int flags) /* Information about what happened. */ { Ttk_TraceHandle *tracePtr = clientData; const char *name, *value; Tcl_Obj *valuePtr; if (flags & TCL_INTERP_DESTROYED) { return NULL; } name = Tcl_GetString(tracePtr->varnameObj); /* * If the variable is being unset, then re-establish the trace: */ if (flags & TCL_TRACE_DESTROYED) { /* |
︙ | ︙ |
Changes to generic/ttk/ttkTreeview.c.
︙ | ︙ | |||
2839 2840 2841 2842 2843 2844 2845 | } tv->tree.yscroll.total = CountRows(tv->tree.root) - 1; /* Make sure item is visible: */ rowNumber = RowNumber(tv, item); if (rowNumber < tv->tree.yscroll.first) { | | | | 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 | } tv->tree.yscroll.total = CountRows(tv->tree.root) - 1; /* Make sure item is visible: */ rowNumber = RowNumber(tv, item); if (rowNumber < tv->tree.yscroll.first) { TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1); } else if (rowNumber >= tv->tree.yscroll.last) { TtkScrollTo(tv->tree.yscrollHandle, tv->tree.yscroll.first + (1+rowNumber - tv->tree.yscroll.last), 1); } return TCL_OK; } /*------------------------------------------------------------------------ * +++ Widget commands -- interactive column resize |
︙ | ︙ |
Changes to generic/ttk/ttkWidget.h.
︙ | ︙ | |||
191 192 193 194 195 196 197 | MODULE_SCOPE ScrollHandle TtkCreateScrollHandle(WidgetCore *, Scrollable *); MODULE_SCOPE void TtkFreeScrollHandle(ScrollHandle); MODULE_SCOPE int TtkScrollviewCommand( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle); | > | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | MODULE_SCOPE ScrollHandle TtkCreateScrollHandle(WidgetCore *, Scrollable *); MODULE_SCOPE void TtkFreeScrollHandle(ScrollHandle); MODULE_SCOPE int TtkScrollviewCommand( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle); MODULE_SCOPE void TtkUpdateScrollInfo(ScrollHandle h); MODULE_SCOPE void TtkScrollTo(ScrollHandle, int newFirst, int updateScrollInfo); MODULE_SCOPE void TtkScrolled(ScrollHandle, int first, int last, int total); MODULE_SCOPE void TtkScrollbarUpdateRequired(ScrollHandle); /* * Tag sets (work in progress, half-baked) */ |
︙ | ︙ |
Changes to library/button.tcl.
︙ | ︙ | |||
744 745 746 747 748 749 750 | proc ::tk::CheckLeave {w} { variable ::tk::Priv if {[$w cget -state] ne "disabled"} { $w configure -state normal } | | | > > > | > | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 | proc ::tk::CheckLeave {w} { variable ::tk::Priv if {[$w cget -state] ne "disabled"} { $w configure -state normal } # Restore the original button "selected" color; but only if the user # has not changed it in the meantime. if {![$w cget -indicatoron] && [info exist Priv($w,selectcolor)]} { if {[$w cget -selectcolor] eq $Priv($w,selectcolor) || ([info exist Priv($w,aselectcolor)] && [$w cget -selectcolor] eq $Priv($w,aselectcolor))} { $w configure -selectcolor $Priv($w,selectcolor) } } unset -nocomplain Priv($w,selectcolor) Priv($w,aselectcolor) # Restore the original button relief if it was changed by Tk. That is # signaled by the existence of Priv($w,prelief). if {[info exists Priv($w,relief)]} { |
︙ | ︙ |
Changes to library/menu.tcl.
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 | set entry "" if {[$button cget -indicatoron]} { set entry [MenuFindName $menu [$button cget -text]] if {$entry eq ""} { set entry 0 } } | < < < < < < < < < | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | set entry "" if {[$button cget -indicatoron]} { set entry [MenuFindName $menu [$button cget -text]] if {$entry eq ""} { set entry 0 } } set x [winfo rootx $button] set y [winfo rooty $button] switch [$button cget -direction] { above { incr y [expr {-[winfo reqheight $menu]}] # if we go offscreen to the top, show as 'below' if {$y < [winfo vrooty $button]} { |
︙ | ︙ |
Changes to library/ttk/aquaTheme.tcl.
1 2 3 4 5 6 7 8 9 | # # Aqua theme (OSX native look and feel) # namespace eval ttk::theme::aqua { ttk::style theme settings aqua { ttk::style configure . \ -font TkDefaultFont \ | | | | | | | < < < < < < < < < < < < < < < < < | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # # Aqua theme (OSX native look and feel) # namespace eval ttk::theme::aqua { ttk::style theme settings aqua { ttk::style configure . \ -font TkDefaultFont \ -background systemWindowBackgroundColor \ -foreground systemLabelColor \ -selectbackground systemHighlight \ -selectforeground systemLabelColor \ -selectborderwidth 0 \ -insertwidth 1 ttk::style map . \ -foreground { disabled systemDisabledControlTextColor background systemLabelColor} \ -selectbackground { background systemSelectedTextBackgroundColor !focus systemSelectedTextBackgroundColor} \ -selectforeground { background systemSelectedTextColor !focus systemSelectedTextColor} # Button ttk::style configure TButton -anchor center -width -6\ -foreground systemControlTextColor ttk::style configure TMenubutton -anchor center -padding {2 0 0 2} ttk::style configure Toolbutton -anchor center # Entry ttk::style configure TEntry \ -foreground systemTextColor \ -background systemTextBackgroundColor \ # Workaround for #1100117: # Actually, on Aqua we probably shouldn't stipple images in # disabled buttons even if it did work... ttk::style configure . -stipple {} # Notebook ttk::style configure TNotebook -tabmargins {10 0} -tabposition n ttk::style configure TNotebook -padding {18 8 18 17} ttk::style configure TNotebook.Tab -padding {12 3 12 2} ttk::style configure TNotebook.Tab -foreground systemControlTextColor ttk::style map TNotebook.Tab \ -foreground { background systemControlTextColor disabled systemDisabledControlTextColor selected systemSelectedTabTextColor} # Combobox: ttk::style configure TCombobox \ -foreground systemTextColor \ -background systemTransparent \ -selectforeground systemSelectedTextColor \ -selectbackground systemSelectedTextBackgroundColor |
︙ | ︙ | |||
103 104 105 106 107 108 109 | !active systemTextColor } \ -selectbackground { !active systemTextBackgroundColor !focus systemTextBackgroundColor focus systemSelectedTextBackgroundColor } | | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | !active systemTextColor } \ -selectbackground { !active systemTextBackgroundColor !focus systemTextBackgroundColor focus systemSelectedTextBackgroundColor } # Treeview: ttk::style configure Heading \ -font TkHeadingFont \ -foreground systemTextColor \ -background systemWindowBackgroundColor ttk::style configure Treeview -rowheight 18 \ -background systemTextBackgroundColor \ -foreground systemTextColor \ -fieldbackground systemTextBackgroundColor ttk::style map Treeview \ -background { selected systemSelectedTextBackgroundColor |
︙ | ︙ |
Changes to library/ttk/combobox.tcl.
︙ | ︙ | |||
247 248 249 250 251 252 253 | ## UnmapPopdown -- <Unmap> binding for ComboboxPopdown # proc ttk::combobox::UnmapPopdown {w} { [winfo parent $w] state !pressed ttk::releaseGrab $w } | < < < < < < < < < < < < < < | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | ## UnmapPopdown -- <Unmap> binding for ComboboxPopdown # proc ttk::combobox::UnmapPopdown {w} { [winfo parent $w] state !pressed ttk::releaseGrab $w } ## PopdownWindow -- # Returns the popdown widget associated with a combobox, # creating it if necessary. # proc ttk::combobox::PopdownWindow {cb} { if {![winfo exists $cb.popdown]} { set poplevel [PopdownToplevel $cb.popdown] set popdown [ttk::frame $poplevel.f -style ComboboxPopdownFrame] ttk::scrollbar $popdown.sb \ -orient vertical -command [list $popdown.l yview] listbox $popdown.l \ -listvariable ttk::combobox::Values($cb) \ -yscrollcommand [list $popdown.sb set] \ -exportselection false \ -selectmode browse \ -activestyle none \ |
︙ | ︙ |
Changes to library/ttk/entry.tcl.
︙ | ︙ | |||
207 208 209 210 211 212 213 | } return $pos } ## See $index -- Make sure that the character at $index is visible. # proc ttk::entry::See {w {index insert}} { | < | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | } return $pos } ## See $index -- Make sure that the character at $index is visible. # proc ttk::entry::See {w {index insert}} { set c [$w index $index] # @@@ OR: check [$w index left] / [$w index right] if {$c < [$w index @0] || $c >= [$w index @[winfo width $w]]} { $w xview $c } } |
︙ | ︙ |
Changes to library/ttk/menubutton.tcl.
︙ | ︙ | |||
57 58 59 60 61 62 63 | bind TMenubutton <ButtonPress-1> \ { %W state pressed ; ttk::menubutton::Popdown %W } bind TMenubutton <ButtonRelease-1> \ { if {[winfo exists %W]} { %W state !pressed } } } # PostPosition -- | | > > > | < > > > | > > > > > > > > > > > > > > | | | > > > | > | > > > > > > > > > > > > > > > > > > > | > > | > | > > | > > | | > > | | > | > | > | > > | < < < | > > > > | > > > | > > | > > > > > > | | | | > | | < > > > > | > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | bind TMenubutton <ButtonPress-1> \ { %W state pressed ; ttk::menubutton::Popdown %W } bind TMenubutton <ButtonRelease-1> \ { if {[winfo exists %W]} { %W state !pressed } } } # PostPosition -- # Returns x and y coordinates and a menu item index. # If the index is not an empty string the menu should # be posted so that the upper left corner of the indexed # menu item is located at the point (x, y). Otherwise # the top left corner of the menu itself should be located # at that point. # # TODO: adjust menu width to be at least as wide as the button # for -direction above, below. # if {[tk windowingsystem] eq "aqua"} { proc ::ttk::menubutton::PostPosition {mb menu} { set menuPad 5 set buttonPad 1 set bevelPad 4 set mh [winfo reqheight $menu] set bh [expr {[winfo height $mb]} + $buttonPad] set bbh [expr {[winfo height $mb]} + $bevelPad] set mw [winfo reqwidth $menu] set bw [winfo width $mb] set dF [expr {[winfo width $mb] - [winfo reqwidth $menu] - $menuPad}] set entry "" set entry [::tk::MenuFindName $menu [$mb cget -text]] if {$entry eq ""} { set entry 0 } set x [winfo rootx $mb] set y [winfo rooty $mb] switch [$mb cget -direction] { above { set entry "" incr y [expr {-$mh + 2 * $menuPad}] } below { set entry "" incr y $bh } left { incr y $menuPad incr x -$mw } right { incr y $menuPad incr x $bw } default { incr y $bbh } } return [list $x $y $entry] } } else { proc ::ttk::menubutton::PostPosition {mb menu} { set mh [expr {[winfo reqheight $menu]}] set bh [expr {[winfo height $mb]}] set mw [expr {[winfo reqwidth $menu]}] set bw [expr {[winfo width $mb]}] set dF [expr {[winfo width $mb] - [winfo reqwidth $menu]}] if {[tk windowingsystem] eq "win32"} { incr mh 6 incr mw 16 } set entry {} set entry [::tk::MenuFindName $menu [$mb cget -text]] if {$entry eq {}} { set entry 0 } set x [winfo rootx $mb] set y [winfo rooty $mb] switch [$mb cget -direction] { above { set entry {} incr y -$mh # if we go offscreen to the top, show as 'below' if {$y < [winfo vrooty $mb]} { set y [expr {[winfo vrooty $mb] + [winfo rooty $mb]\ + [winfo reqheight $mb]}] } } below { set entry {} incr y $bh # if we go offscreen to the bottom, show as 'above' if {($y + $mh) > ([winfo vrooty $mb] + [winfo vrootheight $mb])} { set y [expr {[winfo vrooty $mb] + [winfo vrootheight $mb] \ + [winfo rooty $mb] - $mh}] } } left { incr x -$mw } right { incr x $bw } default { if {[$mb cget -style] eq ""} { incr x [expr {([winfo width $mb] - \ [winfo reqwidth $menu])/ 2}] } else { incr y $bh } } } return [list $x $y $entry] } } # Popdown -- # Post the menu and set a grab on the menu. # proc ttk::menubutton::Popdown {mb} { if {[$mb instate disabled] || [set menu [$mb cget -menu]] eq ""} { return } foreach {x y entry} [PostPosition $mb $menu] { break } tk_popup $menu $x $y $entry } # Pulldown (X11 only) -- # Called when Button1 is pressed on a menubutton. # Posts the menu; a subsequent ButtonRelease # or Leave event will set a grab on the menu. # proc ttk::menubutton::Pulldown {mb} { variable State if {[$mb instate disabled] || [set menu [$mb cget -menu]] eq ""} { return } set State(pulldown) 1 set State(oldcursor) [$mb cget -cursor] $mb state pressed $mb configure -cursor [$menu cget -cursor] foreach {x y entry} [PostPosition $mb $menu] { break } if {$entry ne {}} { $menu post $x $y $entry } else { $menu post $x $y } tk_menuSetFocus $menu } # TransferGrab (X11 only) -- # Switch from pulldown mode (menubutton has an implicit grab) # to popdown mode (menu has an explicit grab). # proc ttk::menubutton::TransferGrab {mb} { variable State if {$State(pulldown)} { $mb configure -cursor $State(oldcursor) $mb state {!pressed !active} set State(pulldown) 0 set menu [$mb cget -menu] foreach {x y entry} [PostPosition $mb $menu] { break } tk_popup $menu [winfo rootx $menu] [winfo rooty $menu] } } # FindMenuEntry -- # Hack to support tk_optionMenus. # Returns the index of the menu entry with a matching -label, |
︙ | ︙ |
Changes to library/ttk/treeview.tcl.
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 | $w focus $item event generate $w <<TreeviewClose>> } ## Toggle -- toggle opened/closed state of item # proc ttk::treeview::Toggle {w item} { if {[$w item $item -open]} { CloseItem $w $item } else { OpenItem $w $item } } | > > > > > > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | $w focus $item event generate $w <<TreeviewClose>> } ## Toggle -- toggle opened/closed state of item # proc ttk::treeview::Toggle {w item} { # don't allow toggling on indicators that # are not present in front of leaf items if {[$w children $item] == {}} { return } # not a leaf, toggle! if {[$w item $item -open]} { CloseItem $w $item } else { OpenItem $w $item } } |
︙ | ︙ |
Changes to macosx/README.
︙ | ︙ | |||
180 181 182 183 184 185 186 | canJoinAllSpaces, moveToActiveSpace, nonActivating Note that not all attributes are valid for all window classes. Support for the 3 argument form was added with the Cocoa-based Tk 8.5.7, at the same time support for some legacy Carbon-specific classes and attributes was removed (they are still accepted by the command but no longer have any effect). | | | | | > | > > > > > > | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | canJoinAllSpaces, moveToActiveSpace, nonActivating Note that not all attributes are valid for all window classes. Support for the 3 argument form was added with the Cocoa-based Tk 8.5.7, at the same time support for some legacy Carbon-specific classes and attributes was removed (they are still accepted by the command but no longer have any effect). - Another command available in the tk::unsupported::MacWindowStyle namespace is: tk::unsupported::MacWindowStyle tabbingid window ?newId? which can be used to get or set the tabbingIdentifier for the NSWindow associated with a Tk Window. See section 3 for details. - The command: tk::unsupported::MacWindowStyle appearance window ?newAappearance? is available when Tk is built and run on macOS 10.14 (Mojave) or later. In that case the Ttk widgets all support the "Dark Mode" appearance which was introduced in 10.14. The command accepts the following values for the optional newAppearance option: "aqua", "darkaqua", or "auto". If the appearance is set to aqua or darkaqua then the window will be displayed with the corresponding appearance independent of any preferences settings. If it is set to "auto" the appearance will be determined by the preferences. This command can be used to opt out of Dark Mode on a per-window basis. - To determine the current appearance of a window in macOS 10.14 (Mojave) and higher, one can use the command: tk::unsupported::MacWindowStyle isdark The boolean return value is true if the window is currently displayed with the dark appearance. - If you want to use Remote Debugging with Xcode, you need to set the environment variable XCNOSTDIN to 1 in the Executable editor for Wish. That will cause us to force closing stdin & stdout. Otherwise, given how Xcode launches Wish remotely, they will be left open and then Wish & gdb will fight for stdin. 3. FullScreen, Split View and Tabbed Windows |
︙ | ︙ | |||
285 286 287 288 289 290 291 | which is already displayed as a tab will also cause it to become a separate window. 4. Ttk, Dark Mode and semantic colors --------------------------------------- With the release of OSX 10.14 (Mojave), Apple introduced the DarkAqua | | | | | > | | | | > | | | | | > > > | | | > | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | which is already displayed as a tab will also cause it to become a separate window. 4. Ttk, Dark Mode and semantic colors --------------------------------------- With the release of OSX 10.14 (Mojave), Apple introduced the DarkAqua appearance. Part of the implementation of the Dark Mode was to make some of the named NSColors have dynamic values. Apple calls these "semantic colors" because the name does not specify a specific color, but rather refers to the context in which the color should be used. Tk now provides the following semantic colors as system colors: systemTextColor, systemTextBackgroundColor, systemSelectedTextColor, systemSelectedTextBackgroundColor, systemControlTextColor, systemDisabledControlTextColor, systemLabelColor, and systemControlAccentColor. All of these except the last two were present in OSX 10.0 (and those two are simulated in systems where they do not exist). The change in 10.14 was that the RGB color value of these colors became dynamic, meaning that the color value can change when the application appearance changes. In particular, when a user selects Dark Mode in the system preferences these colors change appearance. For example systemTextColor is dark in Aqua and light in DarkAqua. One additional color, systemSelectedTabTextColor, does not exist in macOS but is used by Tk to match the different colors used for Notebook tab text in different OS versions. The default background and foreground colors of most of the Tk widgets have been set to semantic colors, which means that the widgets will change appearance, and remain usable, when Dark Mode is selected in the system preferences. However, to get a close match to the native Dark Mode style it is recommended to use Ttk widgets when possible. Apple's tab view and GroupBox objects delimit their content by displaying it within a rounded rectangle with a background color that contrasts with the background of the containing object. This means that the background color of a Ttk widget depends on how deeply it is nested inside of other widgets that use contrasting backgrounds. To support this, there are 8 contrasting system colors named systemWindowBackgroundColor, and systemWindowBackgroundColor1 - 7. The systemWindowBackgroundColor is the standard background for a dialog window and the others match the contrasting background colors used in ttk::notebooks and ttk::labelframes which are nested to the corresponding depth. 5. Building Tcl/Tk on macOS ------------------------------ - At least macOS 10.3 is required to build Tcl and TkX11, and macOS 10.6 is required to build TkAqua. The XCode application provides everything needed to build Tk, but it is not necessary to install the full XCode. |
︙ | ︙ |
Changes to macosx/tkMacOSXButton.c.
1 2 3 | /* * tkMacOSXButton.c -- * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 | /* * tkMacOSXButton.c -- * * This file implements the Macintosh specific portion of the button * widgets. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2006-2007 Daniel A. Steffen <[email protected]> * Copyright 2007 Revar Desmera. * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * Copyright 2015 Marc Culler. |
︙ | ︙ | |||
66 67 68 69 70 71 72 | Tcl_TimerToken defaultPulseHandler; } MacButton; /* * Forward declarations for procedures defined later in this file: */ | < | | > | | | | > | > | | > | > | | < | | | | | < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | Tcl_TimerToken defaultPulseHandler; } MacButton; /* * Forward declarations for procedures defined later in this file: */ static void ButtonBackgroundDrawCB(const HIRect *btnbounds, MacButton *ptr, SInt16 depth, Boolean isColorDev); static void ButtonContentDrawCB(const HIRect *bounds, ThemeButtonKind kind, const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth, Boolean isColorDev); static void ButtonEventProc(ClientData clientData, XEvent *eventPtr); static void TkMacOSXComputeButtonParams(TkButton *butPtr, ThemeButtonKind *btnkind, HIThemeButtonDrawInfo *drawinfo); static int TkMacOSXComputeButtonDrawParams(TkButton *butPtr, DrawParams * dpPtr); static void TkMacOSXDrawButton(MacButton *butPtr, GC gc, Pixmap pixmap); static void DrawButtonImageAndText(TkButton *butPtr); static void PulseDefaultButtonProc(ClientData clientData); /* * The class procedure table for the button widgets. */ const Tk_ClassProcs tkpButtonProcs = { sizeof(Tk_ClassProcs), /* size */ TkButtonWorldChanged, /* worldChangedProc */ }; static int bCount; /* *---------------------------------------------------------------------- * * TkpButtonSetDefaults -- * * This procedure is invoked before option tables are created for buttons. * It modifies some of the default values to match the current values * defined for this platform. * * Results: * Some of the default values in *specPtr are modified. * * Side effects: * Updates some of. * *---------------------------------------------------------------------- */ void TkpButtonSetDefaults() { /*No-op.*/ } /* *---------------------------------------------------------------------- * * TkpCreateButton -- * * Allocate a new TkButton structure. |
︙ | ︙ | |||
137 138 139 140 141 142 143 | *---------------------------------------------------------------------- */ TkButton * TkpCreateButton( Tk_Window tkwin) { | | | | | | | | | | > > > < < < < < < < < > > > > > > > > | > > | > | > > > | > > > | > > > | > | < > > > | | | | | | | | | > | | | > | | | | > > | > > | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | *---------------------------------------------------------------------- */ TkButton * TkpCreateButton( Tk_Window tkwin) { MacButton *macButtonPtr = ckalloc(sizeof(MacButton)); Tk_CreateEventHandler(tkwin, ActivateMask, ButtonEventProc, macButtonPtr); macButtonPtr->id = bCount++; macButtonPtr->flags = FIRST_DRAW; macButtonPtr->btnkind = kThemePushButton; macButtonPtr->defaultPulseHandler = NULL; bzero(&macButtonPtr->drawinfo, sizeof(macButtonPtr->drawinfo)); bzero(&macButtonPtr->lastdrawinfo, sizeof(macButtonPtr->lastdrawinfo)); return (TkButton *) macButtonPtr; } /* *---------------------------------------------------------------------- * * TkpDisplayButton -- * * This procedure is invoked to display a button widget. It is normally * invoked as an idle handler. * * Results: * None. * * Side effects: * Commands are output to X to display the button in its current mode. The * REDRAW_PENDING flag is cleared. * *---------------------------------------------------------------------- */ void TkpDisplayButton( ClientData clientData) /* Information about widget. */ { MacButton *macButtonPtr = clientData; TkButton *butPtr = clientData; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; DrawParams* dpPtr = &macButtonPtr->drawParams; int needhighlight = 0; if (butPtr->flags & BUTTON_DELETED) { return; } butPtr->flags &= ~REDRAW_PENDING; if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } pixmap = (Pixmap) Tk_WindowId(tkwin); /* * Set up clipping region. Make sure the we are using the port * for this button, or we will set the wrong window's clip. */ TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); if (TkMacOSXComputeButtonDrawParams(butPtr, dpPtr)) { macButtonPtr->useTkText = 0; } else { macButtonPtr->useTkText = 1; } if (macButtonPtr->useTkText) { if (butPtr->type == TYPE_BUTTON) { Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } else { Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } /* * Display image or bitmap or text for labels or custom controls. */ DrawButtonImageAndText(butPtr); needhighlight = 1; } else { /* * Draw the native portion of the buttons. */ TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap); /* * Ask for the highlight border, if needed. */ if (butPtr->highlightWidth < 3) { needhighlight = 1; } } /* * Draw highlight border, if needed. */ if (needhighlight) { GC gc = NULL; if ((butPtr->flags & GOT_FOCUS) && butPtr->highlightColorPtr) { gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap); } else if (butPtr->type == TYPE_LABEL) { gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder), pixmap); } if (gc) { TkMacOSXDrawSolidBorder(tkwin, gc, 0, butPtr->highlightWidth); } } } /* *---------------------------------------------------------------------- * * TkpComputeButtonGeometry -- * * After changes in a button's text or bitmap, this procedure recomputes * the button's geometry and passes this information along to the geometry * manager for the window. * * Results: * None. * * Side effects: * The button's window may change size. * *---------------------------------------------------------------------- */ void TkpComputeButtonGeometry( TkButton *butPtr) /* Button whose geometry may have changed. */ { int width = 0, height = 0, charWidth = 1, haveImage = 0, haveText = 0; int txtWidth = 0, txtHeight = 0; MacButton *mbPtr = (MacButton *) butPtr; Tk_FontMetrics fm; char *text = Tcl_GetString(butPtr->textPtr); TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); /* * If the indicator is on, get its size. */ if (butPtr->indicatorOn) { switch (butPtr->type) { case TYPE_RADIO_BUTTON: GetThemeMetric(kThemeMetricRadioButtonWidth, (SInt32 *) &butPtr->indicatorDiameter); break; case TYPE_CHECK_BUTTON: GetThemeMetric(kThemeMetricCheckBoxWidth, (SInt32 *) &butPtr->indicatorDiameter); break; default: break; } /* * Allow 2px extra space next to the indicator. */ butPtr->indicatorSpace = butPtr->indicatorDiameter + 2; } else { butPtr->indicatorSpace = 0; butPtr->indicatorDiameter = 0; } if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); |
︙ | ︙ | |||
304 305 306 307 308 309 310 | txtWidth = butPtr->textWidth + 2*butPtr->padX; txtHeight = butPtr->textHeight + 2*butPtr->padY; haveText = 1; } if (haveImage && haveText) { /* Image and Text */ switch ((enum compound) butPtr->compound) { | | | < | | | | | | | | < | | | | | | | < | | | | | | | | > | > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | txtWidth = butPtr->textWidth + 2*butPtr->padX; txtHeight = butPtr->textHeight + 2*butPtr->padY; haveText = 1; } if (haveImage && haveText) { /* Image and Text */ switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: /* * Image is above or below text. */ height += txtHeight + butPtr->padY; width = (width > txtWidth ? width : txtWidth); break; case COMPOUND_LEFT: case COMPOUND_RIGHT: /* * Image is left or right of text. */ width += txtWidth + 2*butPtr->padX; height = (height > txtHeight ? height : txtHeight); break; case COMPOUND_CENTER: /* * Image and text are superimposed. */ width = (width > txtWidth ? width : txtWidth); height = (height > txtHeight ? height : txtHeight); break; default: break; } width += butPtr->indicatorSpace; } else if (haveImage) { /* Image only */ width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace; height = butPtr->height > 0 ? butPtr->height : height; if (butPtr->type == TYPE_BUTTON) { /* * Allow room to shift the image. */ width += 2; height += 2; } } else { /* Text only */ width = txtWidth + butPtr->indicatorSpace; height = txtHeight; if (butPtr->width > 0) { |
︙ | ︙ | |||
371 372 373 374 375 376 377 | } butPtr->inset = butPtr->borderWidth + butPtr->highlightWidth; width += butPtr->inset*2; height += butPtr->inset*2; if ([NSApp macMinorVersion] == 6) { | | | | | | | | | | | | | | | | < | < | < | < | < | < < < | | | > | > > | < < < < < | | | | | | | | | < | | | < | | | | | | | | | | | | | | | < | | | | | | | | | | | | | < | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | } butPtr->inset = butPtr->borderWidth + butPtr->highlightWidth; width += butPtr->inset*2; height += butPtr->inset*2; if ([NSApp macMinorVersion] == 6) { width += 12; } if (mbPtr->btnkind == kThemePushButton) { HIRect tmpRect; HIRect contBounds; /* * A PushButton has a minimum size. We make sure that we are not * underestimating the size by requesting the content size of a * Pushbutton whose overall size is our content size expanded by the * standard padding. */ tmpRect = CGRectMake(0, 0, width + 2*HI_PADX, height + 2*HI_PADY); HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); if (height < contBounds.size.height) { height = contBounds.size.height; } if (width < contBounds.size.width) { width = contBounds.size.width; } height += 2*HI_PADY; width += 2*HI_PADX; } Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } /* *---------------------------------------------------------------------- * * DrawButtonImageAndText -- * * Draws the image and text associated with a button or label. * * Results: * None. * * Side effects: * The image and text are drawn. * *---------------------------------------------------------------------- */ static void DrawButtonImageAndText( TkButton *butPtr) { MacButton *mbPtr = (MacButton *) butPtr; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; int haveImage = 0, haveText = 0, pressed = 0; int imageWidth = 0, imageHeight = 0; int imageXOffset = 0, imageYOffset = 0; int textXOffset = 0, textYOffset = 0; int width = 0, height = 0; int fullWidth = 0, fullHeight = 0; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } DrawParams *dpPtr = &mbPtr->drawParams; pixmap = (Pixmap) Tk_WindowId(tkwin); if (butPtr->image != None) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); haveImage = 1; } imageWidth = width; imageHeight = height; if (mbPtr->drawinfo.state == kThemeStatePressed) { /* * Offset bitmaps by a bit when the button is pressed. */ pressed = 1; } haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); if (haveImage && haveText) { /* Image and Text */ int x, y; switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: /* Image is above or below text */ if (butPtr->compound == COMPOUND_TOP) { textYOffset = height + butPtr->padY; } else { imageYOffset = butPtr->textHeight + butPtr->padY; } fullHeight = height + butPtr->textHeight + butPtr->padY; fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); textXOffset = (fullWidth - butPtr->textWidth)/2; imageXOffset = (fullWidth - width)/2; break; case COMPOUND_LEFT: case COMPOUND_RIGHT: /* * Image is left or right of text */ if (butPtr->compound == COMPOUND_LEFT) { textXOffset = width + butPtr->padX; } else { imageXOffset = butPtr->textWidth + butPtr->padX; } fullWidth = butPtr->textWidth + butPtr->padX + width; fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); textYOffset = (fullHeight - butPtr->textHeight)/2; imageYOffset = (fullHeight - height)/2; break; case COMPOUND_CENTER: /* * Image and text are superimposed */ fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); textXOffset = (fullWidth - butPtr->textWidth)/2; imageXOffset = (fullWidth - width)/2; textYOffset = (fullHeight - butPtr->textHeight)/2; imageYOffset = (fullHeight - height)/2; break; default: break; } TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, fullWidth + butPtr->indicatorSpace, fullHeight, &x, &y); x += butPtr->indicatorSpace; |
︙ | ︙ | |||
543 544 545 546 547 548 549 | x += dpPtr->offset; y += dpPtr->offset; } imageXOffset += x; imageYOffset += y; if (butPtr->image != NULL) { | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | | | | | | | | | | | | < | < | | > | | | | | | | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 | x += dpPtr->offset; y += dpPtr->offset; } imageXOffset += x; imageYOffset += y; if (butPtr->image != NULL) { if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } } else { XSetClipOrigin(butPtr->display, dpPtr->gc, imageXOffset, imageYOffset); XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, 0, 0, (unsigned int) width, (unsigned int) height, imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } y += 1; /* Tweak to match native buttons. */ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, butPtr->underline); } else if (haveImage) { /* Image only */ int x = 0, y; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, width + butPtr->indicatorSpace, height, &x, &y); x += butPtr->indicatorSpace; if (pressed) { x += dpPtr->offset; y += dpPtr->offset; } imageXOffset += x; imageYOffset += y; if (butPtr->image != NULL) { if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } } else { XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, 0, 0, (unsigned int) width, (unsigned int) height, imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } } else { /* Text only */ int x, y; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->textWidth + butPtr->indicatorSpace, butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; y += 1; /* Tweak to match native buttons */ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x, y, 0, -1); } /* * If the button is disabled with a stipple rather than a special * foreground color, generate the stippled effect. If the widget is * selected and we use a different background color when selected, must * temporarily modify the GC so the stippling is the right color. */ if (mbPtr->useTkText) { if ((butPtr->state == STATE_DISABLED) && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { |
︙ | ︙ | |||
664 665 666 667 668 669 670 | /* * Draw the border and traversal highlight last. This way, if the * button's contents overflow they'll be covered up by the border. */ if (dpPtr->relief != TK_RELIEF_FLAT) { | | > | | | | | < < < < | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | /* * Draw the border and traversal highlight last. This way, if the * button's contents overflow they'll be covered up by the border. */ if (dpPtr->relief != TK_RELIEF_FLAT) { int inset = butPtr->highlightWidth; Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset, Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset, butPtr->borderWidth, dpPtr->relief); } } } /* *---------------------------------------------------------------------- * * TkpDestroyButton -- * * Free data structures associated with the button control. * |
︙ | ︙ | |||
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | */ void TkpDestroyButton( TkButton *butPtr) { MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */ if (mbPtr->defaultPulseHandler) { Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler); } } /* *-------------------------------------------------------------- * * TkMacOSXDrawButton -- * | > | | < | | | | < < | < | < | | | | < | | | < | | > | | | | | | | | | | | | | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 | */ void TkpDestroyButton( TkButton *butPtr) { MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */ if (mbPtr->defaultPulseHandler) { Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler); } } /* *-------------------------------------------------------------- * * TkMacOSXDrawButton -- * * This function draws the tk button using Mac controls. In addition, * this code may apply custom colors passed in the TkButton. * * Results: * None. * * Side effects: * The control is created, or reinitialised as needed * *-------------------------------------------------------------- */ static void TkMacOSXDrawButton( MacButton *mbPtr, /* Mac button. */ GC gc, /* The GC we are drawing into - needed for * the bevel button */ Pixmap pixmap) /* The pixmap we are drawing into - needed * for the bevel button */ { TkButton *butPtr = (TkButton *) mbPtr; TkWindow *winPtr = (TkWindow *) butPtr->tkwin; HIRect cntrRect; TkMacOSXDrawingContext dc; DrawParams *dpPtr = &mbPtr->drawParams; int useNewerHITools = 1; TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin), Tk_Height(butPtr->tkwin)); cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); if (useNewerHITools == 1) { HIRect contHIRec; static HIThemeButtonDrawInfo hiinfo; ButtonBackgroundDrawCB(&cntrRect, mbPtr, 32, true); if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } hiinfo.version = 0; hiinfo.state = mbPtr->drawinfo.state; hiinfo.kind = mbPtr->btnkind; hiinfo.value = mbPtr->drawinfo.value; hiinfo.adornment = mbPtr->drawinfo.adornment; hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent(); if (hiinfo.animation.time.start == 0) { hiinfo.animation.time.start = hiinfo.animation.time.current; } /* * To avoid buttons with white text on a white background, we always * set the state to inactive in Dark Mode. It isn't perfect but it is * usable. Using a ttk::button would be a better choice, however. */ if (TkMacOSXInDarkMode(butPtr->tkwin)) { hiinfo.state = kThemeStateInactive; } HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *) mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } TkMacOSXRestoreDrawingContext(&dc); } mbPtr->lastdrawinfo = mbPtr->drawinfo; } /* *-------------------------------------------------------------- * * ButtonBackgroundDrawCB -- * * This function draws the background that lies under checkboxes and * radiobuttons. * * Results: * None. * * Side effects: * The background gets updated to the current color. * *-------------------------------------------------------------- */ static void ButtonBackgroundDrawCB( const HIRect *btnbounds, MacButton *ptr, SInt16 depth, Boolean isColorDev) { MacButton *mbPtr = (MacButton *) ptr; TkButton *butPtr = (TkButton *) mbPtr; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; int usehlborder = 0; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } pixmap = (Pixmap) Tk_WindowId(tkwin); if (butPtr->type != TYPE_LABEL) { switch (mbPtr->btnkind) { case kThemeSmallBevelButton: case kThemeBevelButton: case kThemeRoundedBevelButton: case kThemePushButton: usehlborder = 1; break; } } if (usehlborder) { Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } else { Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, |
︙ | ︙ | |||
870 871 872 873 874 875 876 | const HIRect * btnbounds, ThemeButtonKind kind, const HIThemeButtonDrawInfo *drawinfo, MacButton *ptr, SInt16 depth, Boolean isColorDev) { | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | const HIRect * btnbounds, ThemeButtonKind kind, const HIThemeButtonDrawInfo *drawinfo, MacButton *ptr, SInt16 depth, Boolean isColorDev) { TkButton *butPtr = (TkButton *) ptr; Tk_Window tkwin = butPtr->tkwin; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } /* * Overlay Tk elements over button native region: drawing elements within * button boundaries/native region causes unpredictable metrics. */ DrawButtonImageAndText( butPtr); } /* *-------------------------------------------------------------- * * ButtonEventProc -- * * This procedure is invoked by the Tk dispatcher for various events on * buttons. * * Results: * None. * * Side effects: * When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void ButtonEventProc( ClientData clientData, /* Information about window. */ XEvent *eventPtr) /* Information about event. */ { TkButton *buttonPtr = clientData; MacButton *mbPtr = clientData; if (eventPtr->type == ActivateNotify || eventPtr->type == DeactivateNotify) { if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) { return; } if (eventPtr->type == ActivateNotify) { mbPtr->flags |= ACTIVE; } else { mbPtr->flags &= ~ACTIVE; } if ((buttonPtr->flags & REDRAW_PENDING) == 0) { Tcl_DoWhenIdle(TkpDisplayButton, buttonPtr); buttonPtr->flags |= REDRAW_PENDING; } } } /* *---------------------------------------------------------------------- * * TkMacOSXComputeButtonParams -- * * This procedure computes the various parameters used when creating a * Carbon Appearance control. These are determined by the various tk * button parameters * * Results: * None. * * Side effects: * Sets the btnkind and drawinfo parameters * *---------------------------------------------------------------------- */ static void TkMacOSXComputeButtonParams( TkButton *butPtr, ThemeButtonKind *btnkind, HIThemeButtonDrawInfo *drawinfo) { MacButton *mbPtr = (MacButton *) butPtr; if (butPtr->borderWidth <= 2) { *btnkind = kThemeSmallBevelButton; } else if (butPtr->borderWidth == 3) { *btnkind = kThemeBevelButton; } else if (butPtr->borderWidth == 4) { *btnkind = kThemeRoundedBevelButton; } else { *btnkind = kThemePushButton; } if ((butPtr->image == None) && (butPtr->bitmap == None)) { switch (butPtr->type) { case TYPE_BUTTON: *btnkind = kThemePushButton; break; case TYPE_RADIO_BUTTON: if (butPtr->borderWidth <= 1) { *btnkind = kThemeSmallRadioButton; } else { *btnkind = kThemeRadioButton; } break; case TYPE_CHECK_BUTTON: if (butPtr->borderWidth <= 1) { *btnkind = kThemeSmallCheckBox; } else { *btnkind = kThemeCheckBox; } break; } } if (butPtr->indicatorOn) { switch (butPtr->type) { case TYPE_RADIO_BUTTON: if (butPtr->borderWidth <= 1) { *btnkind = kThemeSmallRadioButton; } else { *btnkind = kThemeRadioButton; } break; case TYPE_CHECK_BUTTON: if (butPtr->borderWidth <= 1) { *btnkind = kThemeSmallCheckBox; } else { *btnkind = kThemeCheckBox; } break; } } else { if (butPtr->type == TYPE_RADIO_BUTTON || butPtr->type == TYPE_CHECK_BUTTON) { if (*btnkind == kThemePushButton) { *btnkind = kThemeBevelButton; } } } if (butPtr->flags & SELECTED) { |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 | } drawinfo->adornment = kThemeAdornmentNone; if (butPtr->defaultState == DEFAULT_ACTIVE) { drawinfo->adornment |= kThemeAdornmentDefault; if (!mbPtr->defaultPulseHandler) { mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler( | | < | < | | | | | | | | | | | < | < < | < | > | > | | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | } drawinfo->adornment = kThemeAdornmentNone; if (butPtr->defaultState == DEFAULT_ACTIVE) { drawinfo->adornment |= kThemeAdornmentDefault; if (!mbPtr->defaultPulseHandler) { mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler( PULSE_TIMER_MSECS, PulseDefaultButtonProc, butPtr); } } else if (mbPtr->defaultPulseHandler) { Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler); } if (butPtr->highlightWidth >= 3) { if ((butPtr->flags & GOT_FOCUS)) { drawinfo->adornment |= kThemeAdornmentFocus; } } } /* *---------------------------------------------------------------------- * * TkMacOSXComputeButtonDrawParams -- * * This procedure computes the various parameters used when drawing a * button. These are determined by the various tk button parameters * * Results: * 1 if control will be used, 0 otherwise. * * Side effects: * Sets the button draw parameters * *---------------------------------------------------------------------- */ static int TkMacOSXComputeButtonDrawParams( TkButton *butPtr, DrawParams *dpPtr) { MacButton *mbPtr = (MacButton *) butPtr; dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); if (butPtr->type != TYPE_LABEL) { dpPtr->offset = 0; if (dpPtr->hasImageOrBitmap) { switch (mbPtr->btnkind) { case kThemeSmallBevelButton: case kThemeBevelButton: case kThemeRoundedBevelButton: case kThemePushButton: dpPtr->offset = 1; break; } } } dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { dpPtr->gc = butPtr->disabledGC; } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) { dpPtr->gc = butPtr->activeTextGC; dpPtr->border = butPtr->activeBorder; } else { dpPtr->gc = butPtr->normalTextGC; } if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { dpPtr->border = butPtr->selectBorder; } /* * Override the relief specified for the button if this is a checkbutton or * radiobutton and there's no indicator. */ dpPtr->relief = butPtr->relief; if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { if (!dpPtr->hasImageOrBitmap) { dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED; } } if (butPtr->type != TYPE_LABEL && (butPtr->type == TYPE_BUTTON || butPtr->indicatorOn || dpPtr->hasImageOrBitmap)) { /* * Draw this widget as a native control. */ return 1; } else { /* * Draw this widget from scratch. */ return 0; } } /* *-------------------------------------------------------------- * * PulseDefaultButtonProc -- * * This function redraws the button on a timer, to pulse * default buttons. * * Results: * None. * * Side effects: * Sets a timer to run itself again. * *-------------------------------------------------------------- */ static void PulseDefaultButtonProc(ClientData clientData) { MacButton *mbPtr = clientData; TkpDisplayButton(clientData); mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler( PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData); } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXClipboard.c.
︙ | ︙ | |||
119 120 121 122 123 124 125 | * returned. */ Tk_GetSelProc *proc, /* Procedure to call to process the selection, * once it has been retrieved. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { int result = TCL_ERROR; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; | | | > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | * returned. */ Tk_GetSelProc *proc, /* Procedure to call to process the selection, * once it has been retrieved. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { int result = TCL_ERROR; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; int haveExternalClip = ([[NSPasteboard generalPasteboard] changeCount] != changeCount); if (dispPtr && (haveExternalClip || dispPtr->clipboardActive) && selection == dispPtr->clipboardAtom && (target == XA_STRING || target == dispPtr->utf8Atom)) { NSString *string = nil; NSPasteboard *pb = [NSPasteboard generalPasteboard]; NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject: NSStringPboardType]]; |
︙ | ︙ | |||
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | { TkDisplay *dispPtr = TkGetDisplayList(); if (dispPtr && selection == dispPtr->clipboardAtom) { clipboardOwner = owner ? Tk_IdToWindow(display, owner) : NULL; if (!dispPtr->clipboardActive) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; changeCount = [pb declareTypes:[NSArray array] owner:NSApp]; } } return Success; } /* *---------------------------------------------------------------------- * * TkMacOSXSelDeadWindow -- * | > | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | { TkDisplay *dispPtr = TkGetDisplayList(); if (dispPtr && selection == dispPtr->clipboardAtom) { clipboardOwner = owner ? Tk_IdToWindow(display, owner) : NULL; if (!dispPtr->clipboardActive) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; changeCount = [pb declareTypes:[NSArray array] owner:NSApp]; } } return Success; } /* *---------------------------------------------------------------------- * * TkMacOSXSelDeadWindow -- * * This function is invoked just before a TkWindow is deleted. It performs * selection-related cleanup. * * Results: * None. * * Side effects: * clipboardOwner is cleared. * |
︙ | ︙ |
Changes to macosx/tkMacOSXColor.c.
︙ | ︙ | |||
185 186 187 188 189 190 191 | { "WhiteText", HIText, kThemeTextColorWhite }, /* 159 */ { "TabPaneBackground", HIBackground, kThemeBackgroundTabPane }, /* 160 */ { "PlacardBackground", HIBackground, kThemeBackgroundPlacard }, /* 161 */ { "WindowHeaderBackground", HIBackground, kThemeBackgroundWindowHeader }, /* 162 */ { "ListViewWindowHeaderBackground", HIBackground, kThemeBackgroundListViewWindowHeader }, /* 163 */ { "SecondaryGroupBoxBackground", HIBackground, kThemeBackgroundSecondaryGroupBox }, /* 164 */ { "MetalBackground", HIBackground, kThemeBackgroundMetal }, /* 165 */ | > > > > > | | | | | | | | > | | > | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | { "WhiteText", HIText, kThemeTextColorWhite }, /* 159 */ { "TabPaneBackground", HIBackground, kThemeBackgroundTabPane }, /* 160 */ { "PlacardBackground", HIBackground, kThemeBackgroundPlacard }, /* 161 */ { "WindowHeaderBackground", HIBackground, kThemeBackgroundWindowHeader }, /* 162 */ { "ListViewWindowHeaderBackground", HIBackground, kThemeBackgroundListViewWindowHeader }, /* 163 */ { "SecondaryGroupBoxBackground", HIBackground, kThemeBackgroundSecondaryGroupBox }, /* 164 */ { "MetalBackground", HIBackground, kThemeBackgroundMetal }, /* 165 */ /* * Colors based on "semantic" NSColors. */ { "WindowBackgroundColor", ttkBackground, 0 }, /* 166 */ { "WindowBackgroundColor1", ttkBackground, 1 }, /* 167 */ { "WindowBackgroundColor2", ttkBackground, 2 }, /* 168 */ { "WindowBackgroundColor3", ttkBackground, 3 }, /* 169 */ { "WindowBackgroundColor4", ttkBackground, 4 }, /* 170 */ { "WindowBackgroundColor5", ttkBackground, 5 }, /* 171 */ { "WindowBackgroundColor6", ttkBackground, 6 }, /* 172 */ { "WindowBackgroundColor7", ttkBackground, 7 }, /* 173 */ { "TextColor", semantic, 0 }, /* 174 */ { "SelectedTextColor", semantic, 1 }, /* 175 */ { "LabelColor", semantic, 2 }, /* 176 */ { "ControlTextColor", semantic, 3 }, /* 177 */ { "DisabledControlTextColor", semantic, 4 }, /* 178 */ { "SelectedTabTextColor", semantic, 5 }, /* 179 */ { "TextBackgroundColor", semantic, 6 }, /* 180 */ { "SelectedTextBackgroundColor", semantic, 7 }, /* 181 */ { "ControlAccentColor", semantic, 8 }, /* 182 */ { NULL, 0, 0 } }; #define FIRST_SEMANTIC_COLOR 166 #define MAX_PIXELCODE 182 /* *---------------------------------------------------------------------- * * GetEntryFromPixelCode -- * * Extract a SystemColorMapEntry from the table. |
︙ | ︙ | |||
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | * Side effects: * None. * *---------------------------------------------------------------------- */ static NSColorSpace* deviceRGB = NULL; static OSStatus SetCGColorComponents( struct SystemColorMapEntry entry, unsigned long pixel, CGColorRef *c) { OSStatus err = noErr; NSColor *bgColor, *color; CGFloat rgba[4] = {0, 0, 0, 1}; if (!deviceRGB) { deviceRGB = [NSColorSpace deviceRGBColorSpace]; } /* | > > > > > > > > > | | > > > > > > > > > > > | | | > > | > > > > | > | < | < | | < | < > > > > > > > > > | | > | | | > > > > > > > > > > > > > > > > > > > | > < > > > | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | * Side effects: * None. * *---------------------------------------------------------------------- */ static NSColorSpace* deviceRGB = NULL; static CGFloat blueAccentRGBA[4] = {0, 122.0 / 255, 1.0, 1.0}; static CGFloat windowBackground[4] = {236.0 / 255, 236.0 / 255, 236.0 / 255, 1.0}; static OSStatus SetCGColorComponents( struct SystemColorMapEntry entry, unsigned long pixel, CGColorRef *c) { OSStatus err = noErr; NSColor *bgColor, *color; CGFloat rgba[4] = {0, 0, 0, 1}; #if MAC_OS_X_VERSION_MAX_ALLOWED < 101400 NSInteger colorVariant; static CGFloat graphiteAccentRGBA[4] = {152.0 / 255, 152.0 / 255, 152.0 / 255, 1.0}; #endif if (!deviceRGB) { deviceRGB = [NSColorSpace deviceRGBColorSpace]; } /* * This function is called before our autorelease pool is set up, * so it needs its own pool. */ NSAutoreleasePool *pool = [NSAutoreleasePool new]; switch (entry.type) { case HIBrush: err = ChkErr(HIThemeBrushCreateCGColor, entry.value, c); return err; case rgbColor: rgba[0] = ((pixel >> 16) & 0xff) / 255.0; rgba[1] = ((pixel >> 8) & 0xff) / 255.0; rgba[2] = ((pixel ) & 0xff) / 255.0; break; case ttkBackground: /* * Prior to OSX 10.14, getComponents returns black when applied to * windowBackGroundColor. */ if ([NSApp macMinorVersion] < 14) { for (int i=0; i<3; i++) { rgba[i] = windowBackground[i]; } } else { bgColor = [[NSColor windowBackgroundColor] colorUsingColorSpace: deviceRGB]; [bgColor getComponents: rgba]; } if (rgba[0] + rgba[1] + rgba[2] < 1.5) { for (int i=0; i<3; i++) { rgba[i] += entry.value*8.0 / 255.0; } } else { for (int i=0; i<3; i++) { rgba[i] -= entry.value*8.0 / 255.0; } } break; case semantic: switch (entry.value) { case 0: color = [[NSColor textColor] colorUsingColorSpace: deviceRGB]; break; case 1: color = [[NSColor selectedTextColor] colorUsingColorSpace: deviceRGB]; break; case 2: #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 color = [[NSColor labelColor] colorUsingColorSpace: deviceRGB]; #else color = [[NSColor textColor] colorUsingColorSpace: deviceRGB]; #endif break; case 3: color = [[NSColor controlTextColor] colorUsingColorSpace: deviceRGB]; break; case 4: color = [[NSColor disabledControlTextColor] colorUsingColorSpace: deviceRGB]; break; case 5: if ([NSApp macMinorVersion] > 6) { color = [[NSColor whiteColor] colorUsingColorSpace: deviceRGB]; } else { color = [[NSColor blackColor] colorUsingColorSpace: deviceRGB]; } break; case 6: color = [[NSColor textBackgroundColor] colorUsingColorSpace: deviceRGB]; break; case 7: color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpace: deviceRGB]; break; case 8: #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 if (@available(macOS 10.14, *)) { color = [[NSColor controlAccentColor] colorUsingColorSpace: deviceRGB]; } else { color = [NSColor colorWithColorSpace: deviceRGB components: blueAccentRGBA count: 4]; } #else colorVariant = [[NSUserDefaults standardUserDefaults] integerForKey:@"AppleAquaColorVariant"]; if (colorVariant == 6) { color = [NSColor colorWithColorSpace: deviceRGB components: graphiteAccentRGBA count: 4]; } else { color = [NSColor colorWithColorSpace: deviceRGB components: blueAccentRGBA count: 4]; } #endif break; default: #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if ([NSApp macMinorVersion] >= 10) { color = [[NSColor labelColor] colorUsingColorSpace: deviceRGB]; break; } #endif color = [[NSColor textColor] colorUsingColorSpace: deviceRGB]; break; } [color getComponents: rgba]; break; case clearColor: rgba[3] = 0.0; break; /* * There are no HITheme functions which convert Text or background colors * to CGColors. (GetThemeTextColor has been removed, and it was never * possible with backgrounds.) If we get one of these we return black. */ case HIText: case HIBackground: default: break; } *c = CGColorCreate(deviceRGB.CGColorSpace, rgba); [pool drain]; return err; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
378 379 380 381 382 383 384 | * Side effects: * None. * *---------------------------------------------------------------------- */ MODULE_SCOPE Bool | | > > > | < < > | | | > | < < < > < | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | * Side effects: * None. * *---------------------------------------------------------------------- */ MODULE_SCOPE Bool TkMacOSXInDarkMode(Tk_Window tkwin) { int result = false; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 if ([NSApp macMinorVersion] >= 14) { static NSAppearanceName darkAqua = @"NSAppearanceNameDarkAqua"; TkWindow *winPtr = (TkWindow*) tkwin; NSView *view = TkMacOSXDrawableView(winPtr->privatePtr); result = (view && [view.effectiveAppearance.name isEqualToString:darkAqua]); } #endif return result; } /* *---------------------------------------------------------------------- * * TkSetMacColor -- * * Sets the components of a CGColorRef from an XColor pixel value. |
︙ | ︙ | |||
423 424 425 426 427 428 429 430 431 432 433 434 435 436 | TkSetMacColor( unsigned long pixel, /* Pixel value to convert. */ void *macColor) /* CGColorRef to modify. */ { CGColorRef *color = (CGColorRef*)macColor; OSStatus err = -1; struct SystemColorMapEntry entry; if (GetEntryFromPixelCode((pixel >> 24) & 0xff, &entry)) { err = ChkErr(SetCGColorComponents, entry, pixel, color); } return (err == noErr); } /* | > | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | TkSetMacColor( unsigned long pixel, /* Pixel value to convert. */ void *macColor) /* CGColorRef to modify. */ { CGColorRef *color = (CGColorRef*)macColor; OSStatus err = -1; struct SystemColorMapEntry entry; if (GetEntryFromPixelCode((pixel >> 24) & 0xff, &entry)) { err = ChkErr(SetCGColorComponents, entry, pixel, color); } return (err == noErr); } /* |
︙ | ︙ | |||
568 569 570 571 572 573 574 575 576 577 578 579 580 581 | { CGColorRef cgColor = TkMacOSXCreateCGColor(gc, pixel); NSColor *nsColor = nil; if (cgColor) { NSColorSpace *colorSpace = [[NSColorSpace alloc] initWithCGColorSpace:CGColorGetColorSpace(cgColor)]; nsColor = [NSColor colorWithColorSpace:colorSpace components:CGColorGetComponents(cgColor) count:CGColorGetNumberOfComponents(cgColor)]; [colorSpace release]; CFRelease(cgColor); } return nsColor; | > | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | { CGColorRef cgColor = TkMacOSXCreateCGColor(gc, pixel); NSColor *nsColor = nil; if (cgColor) { NSColorSpace *colorSpace = [[NSColorSpace alloc] initWithCGColorSpace:CGColorGetColorSpace(cgColor)]; nsColor = [NSColor colorWithColorSpace:colorSpace components:CGColorGetComponents(cgColor) count:CGColorGetNumberOfComponents(cgColor)]; [colorSpace release]; CFRelease(cgColor); } return nsColor; |
︙ | ︙ | |||
607 608 609 610 611 612 613 | CGContextRef context) { OSStatus err = noErr; CGColorRef cgColor = nil; struct SystemColorMapEntry entry; CGRect rect; int code = (pixel >> 24) & 0xff; | | > | 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | CGContextRef context) { OSStatus err = noErr; CGColorRef cgColor = nil; struct SystemColorMapEntry entry; CGRect rect; int code = (pixel >> 24) & 0xff; HIThemeBackgroundDrawInfo info = {0, kThemeStateActive, 0};; static CGColorSpaceRef deviceRGBSpace = NULL; if (!deviceRGBSpace) { deviceRGBSpace = CGColorSpaceCreateDeviceRGB(); } if (code < FIRST_SEMANTIC_COLOR) { cgColor = CopyCachedColor(gc, pixel); } if (!cgColor && GetEntryFromPixelCode(code, &entry)) { |
︙ | ︙ | |||
630 631 632 633 634 635 636 637 638 639 640 641 642 643 | } break; case HIText: err = ChkErr(HIThemeSetTextFill, entry.value, NULL, context, kHIThemeOrientationNormal); break; case HIBackground: rect = CGContextGetClipBoundingBox(context); err = ChkErr(HIThemeApplyBackground, &rect, &info, context, kHIThemeOrientationNormal); break; default: err = ChkErr(SetCGColorComponents, entry, pixel, &cgColor); if (err == noErr) { | > | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | } break; case HIText: err = ChkErr(HIThemeSetTextFill, entry.value, NULL, context, kHIThemeOrientationNormal); break; case HIBackground: info.kind = entry.value; rect = CGContextGetClipBoundingBox(context); err = ChkErr(HIThemeApplyBackground, &rect, &info, context, kHIThemeOrientationNormal); break; default: err = ChkErr(SetCGColorComponents, entry, pixel, &cgColor); if (err == noErr) { |
︙ | ︙ | |||
689 690 691 692 693 694 695 696 | * Check to see if this is a system color. Otherwise, XParseColor * will do all the work. */ if (strncasecmp(name, "system", 6) == 0) { Tcl_Obj *strPtr = Tcl_NewStringObj(name+6, -1); int idx, result; result = Tcl_GetIndexFromObjStruct(NULL, strPtr, systemColorMap, | > | > | | | | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 | * Check to see if this is a system color. Otherwise, XParseColor * will do all the work. */ if (strncasecmp(name, "system", 6) == 0) { Tcl_Obj *strPtr = Tcl_NewStringObj(name+6, -1); int idx, result; result = Tcl_GetIndexFromObjStruct(NULL, strPtr, systemColorMap, sizeof(struct SystemColorMapEntry), NULL, TCL_EXACT, &idx); Tcl_DecrRefCount(strPtr); if (result == TCL_OK) { OSStatus err; CGColorRef c; unsigned char pixelCode = idx + MIN_PIXELCODE; struct SystemColorMapEntry entry = systemColorMap[idx]; err = ChkErr(SetCGColorComponents, entry, 0, &c); if (err == noErr) { const size_t n = CGColorGetNumberOfComponents(c); const CGFloat *rgba = CGColorGetComponents(c); switch (n) { case 4: color.red = rgba[0] * 65535.0; color.green = rgba[1] * 65535.0; color.blue = rgba[2] * 65535.0; break; case 2: color.red = color.green = color.blue = rgba[0] * 65535.0; break; default: Tcl_Panic("CGColor with %d components", (int) n); } color.pixel = ((((((pixelCode << 8) | ((color.red >> 8) & 0xff)) << 8) | ((color.green >> 8) & 0xff)) << 8) | ((color.blue >> 8) & 0xff)); CGColorRelease(c); goto validXColor; } CGColorRelease(c); } } |
︙ | ︙ |
Changes to macosx/tkMacOSXCursor.c.
︙ | ︙ | |||
181 182 183 184 185 186 187 | {NULL} }; /* * Declarations of static variables used in this file. */ | | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | {NULL} }; /* * Declarations of static variables used in this file. */ static TkMacOSXCursor *gCurrentCursor = NULL; /* A pointer to the current cursor. */ static int gResizeOverride = false; /* A boolean indicating whether we should use * the resize cursor during installations. */ static int gTkOwnsCursor = true;/* A boolean indicating whether Tk owns the * cursor. If not (for instance, in the case * where a Tk window is embedded in another * app's window, and the cursor is out of the * Tk window, we will not attempt to adjust * the cursor. */ /* * Declarations of procedures local to this file */ static void FindCursorByName(TkMacOSXCursor *macCursorPtr, const char *string); |
︙ | ︙ | |||
274 275 276 277 278 279 280 281 282 283 284 285 286 287 | NSBitmapImageRep *bitmapImageRep = NULL; CGImageRef img = NULL, mask = NULL, maskedImg = NULL; static const CGFloat decodeWB[] = {1, 0}; CGColorSpaceRef colorspace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, pix*pix/8, NULL); if (provider) { img = CGImageCreate(pix, pix, 1, 1, pix/8, colorspace, kCGBitmapByteOrderDefault, provider, decodeWB, 0, kCGRenderingIntentDefault); CFRelease(provider); } provider = CGDataProviderCreateWithData(NULL, bitmap + | > | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | NSBitmapImageRep *bitmapImageRep = NULL; CGImageRef img = NULL, mask = NULL, maskedImg = NULL; static const CGFloat decodeWB[] = {1, 0}; CGColorSpaceRef colorspace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, pix*pix/8, NULL); if (provider) { img = CGImageCreate(pix, pix, 1, 1, pix/8, colorspace, kCGBitmapByteOrderDefault, provider, decodeWB, 0, kCGRenderingIntentDefault); CFRelease(provider); } provider = CGDataProviderCreateWithData(NULL, bitmap + |
︙ | ︙ | |||
295 296 297 298 299 300 301 | maskedImg = CGImageCreateWithMask(img, mask); } if (maskedImg) { bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:maskedImg]; CFRelease(maskedImg); } | | > > | > > | > > > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | maskedImg = CGImageCreateWithMask(img, mask); } if (maskedImg) { bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:maskedImg]; CFRelease(maskedImg); } if (mask) { CFRelease(mask); } if (img) { CFRelease(img); } if (colorspace) { CFRelease(colorspace); } if (bitmapImageRep) { image = [[NSImage alloc] initWithSize:NSMakeSize(pix, pix)]; [image addRepresentation:bitmapImageRep]; [bitmapImageRep release]; } uint16_t *hotSpotData = (uint16_t*)(bitmap + 2*pix*pix/8); hotSpot.y = CFSwapInt16BigToHost(*hotSpotData++); hotSpot.x = CFSwapInt16BigToHost(*hotSpotData); haveHotSpot = 1; break; } } |
︙ | ︙ |
Changes to macosx/tkMacOSXDefault.h.
︙ | ︙ | |||
52 53 54 55 56 57 58 | #define DEF_BUTTON_ANCHOR "center" #define DEF_BUTTON_ACTIVE_BG_COLOR ACTIVE_BG #define DEF_BUTTON_ACTIVE_BG_MONO BLACK #define DEF_BUTTON_ACTIVE_FG_COLOR ACTIVE_FG #define DEF_CHKRAD_ACTIVE_FG_COLOR DEF_BUTTON_ACTIVE_FG_COLOR #define DEF_BUTTON_ACTIVE_FG_MONO WHITE | < | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #define DEF_BUTTON_ANCHOR "center" #define DEF_BUTTON_ACTIVE_BG_COLOR ACTIVE_BG #define DEF_BUTTON_ACTIVE_BG_MONO BLACK #define DEF_BUTTON_ACTIVE_FG_COLOR ACTIVE_FG #define DEF_CHKRAD_ACTIVE_FG_COLOR DEF_BUTTON_ACTIVE_FG_COLOR #define DEF_BUTTON_ACTIVE_FG_MONO WHITE #define DEF_BUTTON_BG_COLOR NORMAL_BG #define DEF_BUTTON_BG_MONO WHITE #define DEF_BUTTON_BITMAP "" #define DEF_BUTTON_BORDER_WIDTH "2" #define DEF_BUTTON_CURSOR "" #define DEF_BUTTON_COMMAND "" #define DEF_BUTTON_COMPOUND "none" |
︙ | ︙ | |||
180 181 182 183 184 185 186 | #define DEF_ENTRY_DISABLED_BG_MONO WHITE #define DEF_ENTRY_DISABLED_FG DISABLED #define DEF_ENTRY_EXPORT_SELECTION "1" #define DEF_ENTRY_FONT "TkTextFont" #define DEF_ENTRY_FG NORMAL_FG #define DEF_ENTRY_HIGHLIGHT_BG NORMAL_BG #define DEF_ENTRY_HIGHLIGHT BLACK | < < < | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | #define DEF_ENTRY_DISABLED_BG_MONO WHITE #define DEF_ENTRY_DISABLED_FG DISABLED #define DEF_ENTRY_EXPORT_SELECTION "1" #define DEF_ENTRY_FONT "TkTextFont" #define DEF_ENTRY_FG NORMAL_FG #define DEF_ENTRY_HIGHLIGHT_BG NORMAL_BG #define DEF_ENTRY_HIGHLIGHT BLACK #define DEF_ENTRY_HIGHLIGHT_WIDTH "3" #define DEF_ENTRY_INSERT_BG NORMAL_FG #define DEF_ENTRY_INSERT_BD_COLOR "0" #define DEF_ENTRY_INSERT_BD_MONO "0" #define DEF_ENTRY_INSERT_OFF_TIME "300" #define DEF_ENTRY_INSERT_ON_TIME "600" #define DEF_ENTRY_INSERT_WIDTH "1" #define DEF_ENTRY_JUSTIFY "left" #define DEF_ENTRY_PLACEHOLDER "" #define DEF_ENTRY_PLACEHOLDERFG "#b3b3b3" #define DEF_ENTRY_READONLY_BG_COLOR NORMAL_BG #define DEF_ENTRY_READONLY_BG_MONO WHITE #define DEF_ENTRY_RELIEF "sunken" #define DEF_ENTRY_SCROLL_COMMAND "" #define DEF_ENTRY_SELECT_COLOR SELECT_BG #define DEF_ENTRY_SELECT_MONO BLACK #define DEF_ENTRY_SELECT_BD_COLOR "1" #define DEF_ENTRY_SELECT_BD_MONO "0" #define DEF_ENTRY_SELECT_FG_COLOR SELECT_FG #define DEF_ENTRY_SELECT_FG_MONO WHITE |
︙ | ︙ | |||
340 341 342 343 344 345 346 | /* * Defaults for menubuttons: */ #define DEF_MENUBUTTON_ANCHOR "w" #define DEF_MENUBUTTON_ACTIVE_BG_COLOR ACTIVE_BG | | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | /* * Defaults for menubuttons: */ #define DEF_MENUBUTTON_ANCHOR "w" #define DEF_MENUBUTTON_ACTIVE_BG_COLOR ACTIVE_BG #define DEF_MENUBUTTON_ACTIVE_BG_MONO WHITE #define DEF_MENUBUTTON_ACTIVE_FG_COLOR ACTIVE_FG #define DEF_MENUBUTTON_ACTIVE_FG_MONO BLACK #define DEF_MENUBUTTON_BG_COLOR NORMAL_BG #define DEF_MENUBUTTON_BG_MONO WHITE #define DEF_MENUBUTTON_BITMAP "" #define DEF_MENUBUTTON_BORDER_WIDTH "0" #define DEF_MENUBUTTON_CURSOR "" #define DEF_MENUBUTTON_DIRECTION "below" #define DEF_MENUBUTTON_DISABLED_FG_COLOR DISABLED |
︙ | ︙ |
Changes to macosx/tkMacOSXDialog.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 #define modalOK NSOKButton #define modalCancel NSCancelButton #else #define modalOK NSModalResponseOK #define modalCancel NSModalResponseCancel | | > | > > > | | > | | | > | > | > | | | | | | > | < | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 #define modalOK NSOKButton #define modalCancel NSCancelButton #else #define modalOK NSModalResponseOK #define modalCancel NSModalResponseCancel #endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1090 #define modalOther -1 #define modalError -2 /* * Vars for filtering in "open file" and "save file" dialogs. */ typedef struct { bool doFileTypes; /* Show the accessory view which * displays the filter menu */ bool preselectFilter; /* A filter was selected by the * typevariable. */ bool userHasSelectedFilter; /* The user has changed the filter in * the accessory view. */ NSMutableArray *fileTypeNames; /* Array of names, e.g. "Text * document". */ NSMutableArray *fileTypeExtensions; /* Array of allowed extensions per * name, e.g. "txt", "doc". */ NSMutableArray *fileTypeLabels; /* Displayed string, e.g. "Text * document (.txt, .doc)". */ NSMutableArray *fileTypeAllowsAll; /* Boolean if the all pattern (*.*) is * included. */ NSMutableArray *allowedExtensions; /* Set of all allowed extensions. */ bool allowedExtensionsAllowAll; /* Set of all allowed extensions * includes *.* */ NSUInteger fileTypeIndex; /* Index of currently selected * filter. */ } filepanelFilterInfo; static filepanelFilterInfo filterInfo; static NSOpenPanel *openpanel; static NSSavePanel *savepanel; static const char *const colorOptionStrings[] = { "-initialcolor", "-parent", "-title", NULL }; enum colorOptions { COLOR_INITIAL, COLOR_PARENT, COLOR_TITLE }; |
︙ | ︙ | |||
162 163 164 165 166 167 168 | [TYPE_OKCANCEL] = {3, 4, 0}, [TYPE_RETRYCANCEL] = {1, 4, 0}, [TYPE_YESNO] = {6, 5, 0}, [TYPE_YESNOCANCEL] = {6, 5, 4}, }; /* | | | > | > > > > | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | [TYPE_OKCANCEL] = {3, 4, 0}, [TYPE_RETRYCANCEL] = {1, 4, 0}, [TYPE_YESNO] = {6, 5, 0}, [TYPE_YESNOCANCEL] = {6, 5, 4}, }; /* * Construct a file URL from directory and filename. Either may be nil. If both * are nil, returns nil. */ static NSURL * getFileURL( NSString *directory, NSString *filename) { NSURL *url = nil; if (directory) { url = [NSURL fileURLWithPath:directory isDirectory:YES]; } if (filename) { url = [NSURL URLWithString:filename relativeToURL:url]; } |
︙ | ︙ | |||
225 226 227 228 229 230 231 | } if (callbackInfo->cmdObj) { Tcl_DecrRefCount(callbackInfo->cmdObj); ckfree(callbackInfo); } } | < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | } if (callbackInfo->cmdObj) { Tcl_DecrRefCount(callbackInfo->cmdObj); ckfree(callbackInfo); } } - (void) tkAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo { AlertCallbackInfo *callbackInfo = contextInfo; if (returnCode >= NSAlertFirstButtonReturn) { Tcl_Obj *resultObj = Tcl_NewStringObj(alertButtonStrings[ |
︙ | ︙ | |||
268 269 270 271 272 273 274 | - (void)selectFormat:(id)sender { NSPopUpButton *button = (NSPopUpButton *)sender; filterInfo.fileTypeIndex = [button indexOfSelectedItem]; if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterInfo.fileTypeIndex] boolValue]) { [openpanel setAllowsOtherFileTypes:YES]; | > > | | | > > > > | > | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | - (void)selectFormat:(id)sender { NSPopUpButton *button = (NSPopUpButton *)sender; filterInfo.fileTypeIndex = [button indexOfSelectedItem]; if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterInfo.fileTypeIndex] boolValue]) { [openpanel setAllowsOtherFileTypes:YES]; /* * setAllowsOtherFileTypes might have no effect; it's inherited from * the NSSavePanel, where it has the effect that it does not append an * extension. Setting the allowed file types to nil allows selecting * any file. */ [openpanel setAllowedFileTypes:nil]; } else { NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex]; [openpanel setAllowedFileTypes:allowedtypes]; [openpanel setAllowsOtherFileTypes:NO]; } filterInfo.userHasSelectedFilter = true; } - (void)saveFormat:(id)sender { NSPopUpButton *button = (NSPopUpButton *)sender; filterInfo.fileTypeIndex = [button indexOfSelectedItem]; if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterInfo.fileTypeIndex] boolValue]) { [savepanel setAllowsOtherFileTypes:YES]; [savepanel setAllowedFileTypes:nil]; } else { NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex]; [savepanel setAllowedFileTypes:allowedtypes]; [savepanel setAllowsOtherFileTypes:NO]; } filterInfo.userHasSelectedFilter = true; } |
︙ | ︙ | |||
380 381 382 383 384 385 386 387 388 389 390 391 392 393 | [colorPanel orderOut:NSApp]; [colorPanel setContinuous:NO]; [colorPanel setBecomesKeyOnlyIfNeeded:NO]; [colorPanel setShowsAlpha: NO]; [colorPanel _setUseModalAppearance:YES]; if (title) { NSString *s = [[NSString alloc] initWithUTF8String:title]; [colorPanel setTitle:s]; [s release]; } if (initialColor) { [colorPanel setColor:initialColor]; } returnCode = [NSApp runModalForWindow:colorPanel]; | > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | [colorPanel orderOut:NSApp]; [colorPanel setContinuous:NO]; [colorPanel setBecomesKeyOnlyIfNeeded:NO]; [colorPanel setShowsAlpha: NO]; [colorPanel _setUseModalAppearance:YES]; if (title) { NSString *s = [[NSString alloc] initWithUTF8String:title]; [colorPanel setTitle:s]; [s release]; } if (initialColor) { [colorPanel setColor:initialColor]; } returnCode = [NSApp runModalForWindow:colorPanel]; |
︙ | ︙ | |||
411 412 413 414 415 416 417 | } result = TCL_OK; end: return result; } | > | | > > > > > > | > > | > | | | > | > > | | | | | > > > | > > | > > | > > | > | > > | > > | > > | > > | > > < | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | } result = TCL_OK; end: return result; } /* * Dissect the -filetype nested lists and store the information in the * filterInfo structure. */ static int parseFileFilters( Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVariablePtr) { if (!fileTypesPtr) { filterInfo.doFileTypes = false; return TCL_OK; } FileFilterList fl; TkInitFileFilters(&fl); if (TkGetFileFilters(interp, &fl, fileTypesPtr, 0) != TCL_OK) { TkFreeFileFilters(&fl); return TCL_ERROR; } filterInfo.doFileTypes = (fl.filters != NULL); filterInfo.fileTypeIndex = 0; filterInfo.fileTypeExtensions = [NSMutableArray array]; filterInfo.fileTypeNames = [NSMutableArray array]; filterInfo.fileTypeLabels = [NSMutableArray array]; filterInfo.fileTypeAllowsAll = [NSMutableArray array]; filterInfo.allowedExtensions = [NSMutableArray array]; filterInfo.allowedExtensionsAllowAll = NO; if (filterInfo.doFileTypes) { for (FileFilter *filterPtr = fl.filters; filterPtr; filterPtr = filterPtr->next) { NSString *name = [[NSString alloc] initWithUTF8String: filterPtr->name]; [filterInfo.fileTypeNames addObject:name]; [name release]; NSMutableArray *clauseextensions = [NSMutableArray array]; NSMutableArray *displayextensions = [NSMutableArray array]; bool allowsAll = NO; for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr; clausePtr = clausePtr->next) { for (GlobPattern *globPtr = clausePtr->patterns; globPtr; globPtr = globPtr->next) { const char *str = globPtr->pattern; while (*str && (*str == '*' || *str == '.')) { str++; } if (*str) { NSString *extension = [[NSString alloc] initWithUTF8String:str]; if (![filterInfo.allowedExtensions containsObject:extension]) { [filterInfo.allowedExtensions addObject:extension]; } [clauseextensions addObject:extension]; [displayextensions addObject:[@"." stringByAppendingString:extension]]; [extension release]; } else { /* * It is the all pattern (*, .* or *.*) */ allowsAll = YES; filterInfo.allowedExtensionsAllowAll = YES; [displayextensions addObject:@"*"]; } } } [filterInfo.fileTypeExtensions addObject:clauseextensions]; [filterInfo.fileTypeAllowsAll addObject:[NSNumber numberWithBool:allowsAll]]; NSMutableString *label = [[NSMutableString alloc] initWithString:name]; [label appendString:@" ("]; [label appendString:[displayextensions componentsJoinedByString:@", "]]; [label appendString:@")"]; [filterInfo.fileTypeLabels addObject:label]; [label release]; } /* * Check if the typevariable exists and matches one of the names. */ filterInfo.preselectFilter = false; filterInfo.userHasSelectedFilter = false; if (typeVariablePtr) { /* * Extract the variable content as a NSString. */ Tcl_Obj *selectedFileTypeObj = Tcl_ObjGetVar2(interp, typeVariablePtr, NULL, TCL_GLOBAL_ONLY); /* * Check that the typevariable exists. */ if (selectedFileTypeObj != NULL) { const char *selectedFileType = Tcl_GetString(selectedFileTypeObj); NSString *selectedFileTypeStr = [[NSString alloc] initWithUTF8String:selectedFileType]; NSUInteger index = [filterInfo.fileTypeNames indexOfObject:selectedFileTypeStr]; if (index != NSNotFound) { filterInfo.fileTypeIndex = index; filterInfo.preselectFilter = true; } } } } TkFreeFileFilters(&fl); return TCL_OK; } static bool filterCompatible( NSString *extension, int filterIndex) { NSMutableArray *allowedExtensions = [filterInfo.fileTypeExtensions objectAtIndex: filterIndex]; /* * If this contains the all pattern, accept any extension. */ if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterIndex] boolValue]) { return true; } return [allowedExtensions containsObject: extension]; } /* *---------------------------------------------------------------------- * * Tk_GetOpenFileObjCmd -- * * This procedure implements the "open file" dialog box for the Mac |
︙ | ︙ | |||
627 628 629 630 631 632 633 | break; } } if (title) { [openpanel setTitle:title]; | > | | | | > | > > | | > > | > > > | | > > > > | > > | > > | | > | | | > | > | | > | | | > > > > | | > | | > > > > | | > > | > < | > < < > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 | break; } } if (title) { [openpanel setTitle:title]; /* * From OSX 10.11, the title string is silently ignored in the open * panel. Prepend the title to the message in this case. NOTE should * be conditional on OSX version, but -mmacosx-version-min does not * revert this behaviour */ if (message) { NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@", title, message]; [message release]; [title release]; message = fullmessage; } else { message = title; } } if (message) { [openpanel setMessage:message]; [message release]; } [openpanel setAllowsMultipleSelection:multiple]; if (parseFileFilters(interp, fileTypesPtr, typeVariablePtr) != TCL_OK) { goto end; } if (filterInfo.doFileTypes) { NSView *accessoryView = [[NSView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)]; NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)]; [label setEditable:NO]; [label setStringValue:@"Filter:"]; [label setBordered:NO]; [label setBezeled:NO]; [label setDrawsBackground:NO]; NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 240, 22.0) pullsDown:NO]; [popupButton addItemsWithTitles:filterInfo.fileTypeLabels]; [popupButton setAction:@selector(selectFormat:)]; [accessoryView addSubview:label]; [accessoryView addSubview:popupButton]; if (filterInfo.preselectFilter) { /* * A specific filter was selected from the typevariable. Select it * and open the accessory view. */ [popupButton selectItemAtIndex:filterInfo.fileTypeIndex]; /* * On OSX > 10.11, the options are not visible by default. Ergo * allow all file types [openpanel setAllowedFileTypes:filterInfo.fileTypeExtensions[filterInfo.fileTypeIndex]]; */ [openpanel setAllowedFileTypes:filterInfo.allowedExtensions]; } else { [openpanel setAllowedFileTypes:filterInfo.allowedExtensions]; } if (filterInfo.allowedExtensionsAllowAll) { [openpanel setAllowsOtherFileTypes:YES]; } else { [openpanel setAllowsOtherFileTypes:NO]; } [openpanel setAccessoryView:accessoryView]; } else { /* * No filters are given. Allow picking all files. */ [openpanel setAllowsOtherFileTypes:YES]; } if (cmdObj) { callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo)); if (Tcl_IsShared(cmdObj)) { cmdObj = Tcl_DuplicateObj(cmdObj); } Tcl_IncrRefCount(cmdObj); } callbackInfo->cmdObj = cmdObj; callbackInfo->interp = interp; callbackInfo->multiple = multiple; parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { parentIsKey = [parent isKeyWindow]; if (directory || filename) { NSURL *fileURL = getFileURL(directory, filename); [openpanel setDirectoryURL:fileURL]; } [openpanel beginSheetModalForWindow:parent completionHandler:^(NSInteger returnCode) { [NSApp tkFilePanelDidEnd:openpanel returnCode:returnCode contextInfo:callbackInfo ]; }]; modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:openpanel]; } else { if (directory || filename) { NSURL *fileURL = getFileURL(directory, filename); [openpanel setDirectoryURL:fileURL]; } modalReturnCode = [openpanel runModal]; [NSApp tkFilePanelDidEnd:openpanel returnCode:modalReturnCode contextInfo:callbackInfo]; } result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR; if (parentIsKey) { [parent makeKeyWindow]; } if ((typeVariablePtr && (modalReturnCode == NSOKButton)) && filterInfo.doFileTypes) { /* * The -typevariable must be set to the selected file type, if the * dialog was not cancelled. */ NSUInteger selectedFilterIndex = filterInfo.fileTypeIndex; NSString *selectedFilter = NULL; if (filterInfo.userHasSelectedFilter) { selectedFilterIndex = filterInfo.fileTypeIndex; selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex]; } else { /* * Difficult case: the user has not touched the filter settings, * but we must return something in the typevariable. First check if * the preselected type is compatible with the selected file, * otherwise choose the first compatible type from the list, * finally fall back to the empty string. */ NSURL *selectedFile; if (multiple) { /* * Use the first file in the case of multiple selection. * Anyway it is not overly useful here. */ selectedFile = [[openpanel URLs] objectAtIndex:0]; } else { selectedFile = [openpanel URL]; } NSString *extension = [selectedFile pathExtension]; if (filterInfo.preselectFilter && filterCompatible(extension, filterInfo.fileTypeIndex)) { selectedFilterIndex = filterInfo.fileTypeIndex; // The preselection from the typevariable selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex]; } else { // scan the list NSUInteger i; for (i = 0; i < [filterInfo.fileTypeNames count]; i++) { if (filterCompatible(extension, i)) { selectedFilterIndex = i; break; } } if (i == selectedFilterIndex) { selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex]; } else { selectedFilter = @""; } } } Tcl_ObjSetVar2(interp, typeVariablePtr, NULL, Tcl_NewStringObj([selectedFilter UTF8String], -1), TCL_GLOBAL_ONLY); } end: return result; } /* *---------------------------------------------------------------------- * * Tk_GetSaveFileObjCmd -- * * This procedure implements the "save file" dialog box for the Mac * platform. See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See user documentation. * *---------------------------------------------------------------------- */ int Tk_GetSaveFileObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ |
︙ | ︙ | |||
824 825 826 827 828 829 830 | int index, len; Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL, *fileTypesPtr = NULL; FilePanelCallbackInfo callbackInfoStruct; FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; NSString *directory = nil, *filename = nil, *defaultType = nil; NSString *message = nil, *title = nil; NSWindow *parent; | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | int index, len; Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL, *fileTypesPtr = NULL; FilePanelCallbackInfo callbackInfoStruct; FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; NSString *directory = nil, *filename = nil, *defaultType = nil; NSString *message = nil, *title = nil; NSWindow *parent; savepanel = [NSSavePanel savePanel]; NSInteger modalReturnCode = modalError; BOOL parentIsKey = NO; for (i = 1; i < objc; i += 2) { if (Tcl_GetIndexFromObjStruct(interp, objv[i], saveOptionStrings, sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) { goto end; |
︙ | ︙ | |||
902 903 904 905 906 907 908 | break; } } if (title) { [savepanel setTitle:title]; | > | | | | > > > | > | | > > | > > > | | | > > > | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 | break; } } if (title) { [savepanel setTitle:title]; /* * From OSX 10.11, the title string is silently ignored, if the save * panel is a sheet. Prepend the title to the message in this case. * NOTE: should be conditional on OSX version, but -mmacosx-version-min * does not revert this behaviour. */ if (haveParentOption) { if (message) { NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@",title,message]; [message release]; [title release]; message = fullmessage; } else { message = title; } } } if (message) { [savepanel setMessage:message]; [message release]; } if (parseFileFilters(interp, fileTypesPtr, typeVariablePtr) != TCL_OK) { goto end; } if (filterInfo.doFileTypes) { NSView *accessoryView = [[NSView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)]; NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)]; [label setEditable:NO]; [label setStringValue:NSLocalizedString(@"Format:", nil)]; [label setBordered:NO]; [label setBezeled:NO]; [label setDrawsBackground:NO]; NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 340, 22.0) pullsDown:NO]; [popupButton addItemsWithTitles:filterInfo.fileTypeLabels]; [popupButton selectItemAtIndex:filterInfo.fileTypeIndex]; [popupButton setAction:@selector(saveFormat:)]; [accessoryView addSubview:label]; [accessoryView addSubview:popupButton]; [savepanel setAccessoryView:accessoryView]; [savepanel setAllowedFileTypes:[filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex]]; [savepanel setAllowsOtherFileTypes:filterInfo.allowedExtensionsAllowAll]; } else if (defaultType) { /* * If no filetypes are given, defaultextension is an alternative way to * specify the attached extension. Just propose this extension, but * don't display an accessory view. */ NSMutableArray *AllowedFileTypes = [NSMutableArray array]; [AllowedFileTypes addObject:defaultType]; [savepanel setAllowedFileTypes:AllowedFileTypes]; [savepanel setAllowsOtherFileTypes:YES]; } [savepanel setCanSelectHiddenExtension:YES]; [savepanel setExtensionHidden:NO]; |
︙ | ︙ | |||
974 975 976 977 978 979 980 | } callbackInfo->cmdObj = cmdObj; callbackInfo->interp = interp; callbackInfo->multiple = 0; parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { | | | > > | > > > | | | > | > > > | > > > | > | > > > | | > < | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | } callbackInfo->cmdObj = cmdObj; callbackInfo->interp = interp; callbackInfo->multiple = 0; parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { parentIsKey = [parent isKeyWindow]; if (directory) { [savepanel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]]; } /* * Check for file name, otherwise set to empty string; crashes with * uncaught exception if set to nil. */ if (filename) { [savepanel setNameFieldStringValue:filename]; } else { [savepanel setNameFieldStringValue:@""]; } [savepanel beginSheetModalForWindow:parent completionHandler:^(NSInteger returnCode) { [NSApp tkFilePanelDidEnd:savepanel returnCode:returnCode contextInfo:callbackInfo]; }]; modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:savepanel]; } else { if (directory) { [savepanel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]]; } /* * Check for file name, otherwise set to empty string; crashes with * uncaught exception if set to nil. */ if (filename) { [savepanel setNameFieldStringValue:filename]; } else { [savepanel setNameFieldStringValue:@""]; } modalReturnCode = [savepanel runModal]; [NSApp tkFilePanelDidEnd:savepanel returnCode:modalReturnCode contextInfo:callbackInfo]; } result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR; if (parentIsKey) { [parent makeKeyWindow]; } if (typeVariablePtr && (modalReturnCode == NSOKButton) && filterInfo.doFileTypes) { /* * The -typevariable must be set to the selected file type, if the * dialog was not cancelled. */ NSString *selectedFilter = [filterInfo.fileTypeNames objectAtIndex:filterInfo.fileTypeIndex]; Tcl_ObjSetVar2(interp, typeVariablePtr, NULL, Tcl_NewStringObj([selectedFilter UTF8String], -1), TCL_GLOBAL_ONLY); } end: return result; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1126 1127 1128 1129 1130 1131 1132 | cmdObj = Tcl_DuplicateObj(cmdObj); } Tcl_IncrRefCount(cmdObj); } callbackInfo->cmdObj = cmdObj; callbackInfo->interp = interp; callbackInfo->multiple = 0; | > > | > > > | | | | > | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 | cmdObj = Tcl_DuplicateObj(cmdObj); } Tcl_IncrRefCount(cmdObj); } callbackInfo->cmdObj = cmdObj; callbackInfo->interp = interp; callbackInfo->multiple = 0; /* * Check for directory value, set to root if not specified; otherwise * crashes with exception because of nil string parameter. */ if (!directory) { directory = @"/"; } parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { parentIsKey = [parent isKeyWindow]; [panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]]; [panel beginSheetModalForWindow:parent completionHandler:^(NSInteger returnCode) { [NSApp tkFilePanelDidEnd:panel returnCode:returnCode contextInfo:callbackInfo]; }]; modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel]; } else { [panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]]; modalReturnCode = [panel runModal]; [NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode contextInfo:callbackInfo]; } |
︙ | ︙ | |||
1197 1198 1199 1200 1201 1202 1203 | /* * This replaces the old about dialog with a standard alert that displays * correctly on 10.14. */ NSString *version = @"Tcl " TCL_PATCH_LEVEL " & Tk " TCL_PATCH_LEVEL; | | > | | > | > | 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 | /* * This replaces the old about dialog with a standard alert that displays * correctly on 10.14. */ NSString *version = @"Tcl " TCL_PATCH_LEVEL " & Tk " TCL_PATCH_LEVEL; NSString *url = @"www.tcl-lang.org"; NSTextView *credits = [[NSTextView alloc] initWithFrame:NSMakeRect(0,0,300,300)]; NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; NSDictionary *textAttributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; [credits insertText: [[NSAttributedString alloc] initWithString:[NSString stringWithFormat: @"\n" "Tcl and Tk are distributed under a modified BSD license: " "www.tcl.tk/software/tcltk/license.html\n\n" "%1$C 1987-%2$@ Tcl Core Team and Contributers.\n\n" "%1$C 2011-%2$@ Kevin Walzer/WordTech Communications LLC.\n\n" "%1$C 2014-%2$@ Marc Culler.\n\n" "%1$C 2002-2012 Daniel A. Steffen.\n\n" "%1$C 2001-2009 Apple Inc.\n\n" "%1$C 2001-2002 Jim Ingham & Ian Reid\n\n" "%1$C 1998-2000 Jim Ingham & Ray Johnson\n\n" "%1$C 1998-2000 Scriptics Inc.\n\n" "%1$C 1996-1997 Sun Microsystems Inc.", 0xA9, year] attributes:textAttributes] replacementRange:NSMakeRange(0,0)]; [credits setDrawsBackground:NO]; [credits setEditable:NO]; NSAlert *about = [[NSAlert alloc] init]; [[about window] setTitle:@"About Tcl & Tk"]; [about setMessageText: version]; [about setInformativeText:url]; about.accessoryView = credits; [about runModal]; [about release]; } |
︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 | if (indexDefaultOption) { /* * Any '-default' option needs to know the '-type' option, which is * why we do this here. */ if (Tcl_GetIndexFromObjStruct(interp, objv[indexDefaultOption + 1], | | > | | 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 | if (indexDefaultOption) { /* * Any '-default' option needs to know the '-type' option, which is * why we do this here. */ if (Tcl_GetIndexFromObjStruct(interp, objv[indexDefaultOption + 1], alertButtonStrings, sizeof(char *), "-default value", TCL_EXACT, &index) != TCL_OK) { goto end; } /* * Need to map from "ok" etc. to 1, 2, 3, right to left. */ defaultNativeButtonIndex = alertButtonIndexAndTypeToNativeButtonIndex[typeIndex][index]; if (!defaultNativeButtonIndex) { Tcl_SetObjResult(interp, Tcl_NewStringObj("Illegal default option", -1)); Tcl_SetErrorCode(interp, "TK", "MSGBOX", "DEFAULT", NULL); goto end; } } [alert setIcon:[NSApp applicationIconImage]]; [alert setAlertStyle:alertStyles[iconIndex]]; i = 0; while (i < 3 && alertButtonNames[typeIndex][i]) { [alert addButtonWithTitle:(NSString*) alertButtonNames[typeIndex][i++]]; } buttons = [alert buttons]; for (NSButton *b in buttons) { NSString *ke = [b keyEquivalent]; if (([ke isEqualToString:@"\r"] || [ke isEqualToString:@"\033"]) && ![b keyEquivalentModifierMask]) { |
︙ | ︙ | |||
1424 1425 1426 1427 1428 1429 1430 | callbackInfo->interp = interp; callbackInfo->typeIndex = typeIndex; parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { parentIsKey = [parent isKeyWindow]; #if MAC_OS_X_VERSION_MIN_REQUIRED > 1090 [alert beginSheetModalForWindow:parent | | | | | > | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 | callbackInfo->interp = interp; callbackInfo->typeIndex = typeIndex; parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); if (haveParentOption && parent && ![parent attachedSheet]) { parentIsKey = [parent isKeyWindow]; #if MAC_OS_X_VERSION_MIN_REQUIRED > 1090 [alert beginSheetModalForWindow:parent completionHandler:^(NSModalResponse returnCode) { [NSApp tkAlertDidEnd:alert returnCode:returnCode contextInfo:callbackInfo]; }]; #else [alert beginSheetModalForWindow:parent modalDelegate:NSApp didEndSelector:@selector(tkAlertDidEnd:returnCode:contextInfo:) contextInfo:callbackInfo]; #endif modalReturnCode = cmdObj ? 0 : |
︙ | ︙ | |||
1467 1468 1469 1470 1471 1472 1473 | typedef struct FontchooserData { Tcl_Obj *titleObj; Tcl_Obj *cmdObj; Tk_Window parent; } FontchooserData; | | > > > | 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 | typedef struct FontchooserData { Tcl_Obj *titleObj; Tcl_Obj *cmdObj; Tk_Window parent; } FontchooserData; enum FontchooserEvent { FontchooserClosed, FontchooserSelection }; static void FontchooserEvent(int kind); static Tcl_Obj * FontchooserCget(FontchooserData *fcdPtr, int optionIndex); static int FontchooserConfigureCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); |
︙ | ︙ | |||
1559 1560 1561 1562 1563 1564 1565 | @end /* *---------------------------------------------------------------------- * * FontchooserEvent -- * | | | | 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | @end /* *---------------------------------------------------------------------- * * FontchooserEvent -- * * This processes events generated by user interaction with the font * panel. * * Results: * None. * * Side effects: * Additional events may be place on the Tk event queue. * |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 | } /* *---------------------------------------------------------------------- * * FontchooserCget -- * | | | < | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 | } /* *---------------------------------------------------------------------- * * FontchooserCget -- * * Helper for the FontchooserConfigure command to return the current value * of any of the options (which may be NULL in the structure). * * Results: * Tcl object of option value. * * Side effects: * None. * |
︙ | ︙ | |||
1684 1685 1686 1687 1688 1689 1690 | } /* * ---------------------------------------------------------------------- * * FontchooserConfigureCmd -- * | | | | 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 | } /* * ---------------------------------------------------------------------- * * FontchooserConfigureCmd -- * * Implementation of the 'tk fontchooser configure' ensemble command. See * the user documentation for what it does. * * Results: * See the user documentation. * * Side effects: * Per-interp data structure may be modified * |
︙ | ︙ | |||
1818 1819 1820 1821 1822 1823 1824 | NSFontPanel *fp = [fm fontPanel:NO]; [fp setPanelFont:fontPanelFont isMultiple:NO]; [fm setSelectedFont:fontPanelFont isMultiple:NO]; [fm setSelectedAttributes:fontPanelFontAttributes isMultiple:NO]; if ([fp isVisible]) { | | > | 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 | NSFontPanel *fp = [fm fontPanel:NO]; [fp setPanelFont:fontPanelFont isMultiple:NO]; [fm setSelectedFont:fontPanelFont isMultiple:NO]; [fm setSelectedAttributes:fontPanelFontAttributes isMultiple:NO]; if ([fp isVisible]) { TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged", NULL); } break; case FontchooserCmd: if (fcdPtr->cmdObj) { Tcl_DecrRefCount(fcdPtr->cmdObj); } Tcl_GetStringFromObj(objv[i+1], &len); |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | } /* * ---------------------------------------------------------------------- * * FontchooserShowCmd -- * | | | | | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 | } /* * ---------------------------------------------------------------------- * * FontchooserShowCmd -- * * Implements the 'tk fontchooser show' ensemble command. The per-interp * configuration data for the dialog is held in an interp associated * structure. * * Results: * See the user documentation. * * Side effects: * Font Panel may be shown. * |
︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 | NULL); if (fcdPtr->parent == None) { fcdPtr->parent = (Tk_Window) clientData; Tk_CreateEventHandler(fcdPtr->parent, StructureNotifyMask, FontchooserParentEventHandler, fcdPtr); } NSFontManager *fm = [NSFontManager sharedFontManager]; NSFontPanel *fp = [fm fontPanel:YES]; if ([fp delegate] != NSApp) { [fp setDelegate:NSApp]; } if (![fp isVisible]) { [fm orderFrontFontPanel:NSApp]; TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility", NULL); } fontchooserInterp = interp; return TCL_OK; } /* * ---------------------------------------------------------------------- * * FontchooserHideCmd -- * | > > | | > | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 | NULL); if (fcdPtr->parent == None) { fcdPtr->parent = (Tk_Window) clientData; Tk_CreateEventHandler(fcdPtr->parent, StructureNotifyMask, FontchooserParentEventHandler, fcdPtr); } NSFontManager *fm = [NSFontManager sharedFontManager]; NSFontPanel *fp = [fm fontPanel:YES]; if ([fp delegate] != NSApp) { [fp setDelegate:NSApp]; } if (![fp isVisible]) { [fm orderFrontFontPanel:NSApp]; TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility", NULL); } fontchooserInterp = interp; return TCL_OK; } /* * ---------------------------------------------------------------------- * * FontchooserHideCmd -- * * Implementation of the 'tk fontchooser hide' ensemble. See the user * documentation for details. * * Results: * See the user documentation. * * Side effects: * Font Panel may be hidden. * * ---------------------------------------------------------------------- */ static int FontchooserHideCmd( ClientData clientData, /* Main window */ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { NSFontPanel *fp = [[NSFontManager sharedFontManager] fontPanel:NO]; if ([fp isVisible]) { [fp orderOut:NSApp]; } return TCL_OK; } /* |
︙ | ︙ | |||
1993 1994 1995 1996 1997 1998 1999 | } /* * ---------------------------------------------------------------------- * * TkInitFontchooser -- * | | | | 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 | } /* * ---------------------------------------------------------------------- * * TkInitFontchooser -- * * Associate the font chooser configuration data with the Tcl interpreter. * There is one font chooser per interp. * * Results: * None. * * Side effects: * per-interp configuration data is destroyed. * |
︙ | ︙ |
Changes to macosx/tkMacOSXDraw.c.
1 2 3 | /* * tkMacOSXDraw.c -- * | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 | /* * tkMacOSXDraw.c -- * * This file contains functions that perform drawing to Xlib windows. Most * of the functions simple emulate Xlib functions. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright 2014 Marc Culler. * * See the file "license.terms" for information on usage and redistribution |
︙ | ︙ | |||
27 28 29 30 31 32 33 | /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_DRAWING #define TK_MAC_DEBUG_IMAGE_DRAWING #endif */ | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_DRAWING #define TK_MAC_DEBUG_IMAGE_DRAWING #endif */ #define radians(d) ((d) * (M_PI/180.0)) /* * Non-antialiased CG drawing looks better and more like X11 drawing when using * very fine lines, so decrease all linewidths by the following constant. */ #define NON_AA_CG_OFFSET .999 static int cgAntiAliasLimit = 0; #define notAA(w) ((w) < cgAntiAliasLimit) static int useThemedToplevel = 0; static int useThemedFrame = 0; /* * Prototypes for functions used only in this file. */ |
︙ | ︙ | |||
115 116 117 118 119 120 121 | * implementation does not work correctly. Originally it relied on * [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was * deprecated by Apple in OSX 10.14 and also required the use of other * deprecated functions such as [NSView lockFocus]. Apple's suggested * replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that * is what is being used here. However, that method only works when the * view has a valid CGContext, and a view is only guaranteed to have a | | | | | | | | | | | | | | > | | | | | | | | | < < > > | | | | < | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | * implementation does not work correctly. Originally it relied on * [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was * deprecated by Apple in OSX 10.14 and also required the use of other * deprecated functions such as [NSView lockFocus]. Apple's suggested * replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that * is what is being used here. However, that method only works when the * view has a valid CGContext, and a view is only guaranteed to have a * valid context during a call to [NSView drawRect]. To further complicate * matters, cacheDisplayInRect calls [NSView drawRect]. Essentially it is * asking the view to draw a subrectangle of itself into a special * graphics context which is linked to the BitmapImageRep. But our * implementation of [NSView drawRect] does not allow recursive calls. If * called recursively it returns immediately without doing any drawing. * So the bottom line is that this function either returns a NULL pointer * or a black image. To make it useful would require a significant amount * of rewriting of the drawRect method. Perhaps the next release of OSX * will include some more helpful ways of doing this. * * Results: * Returns an NSBitmapRep representing the image of the given rectangle of * the given drawable. This object is retained. The caller is responsible * for releasing it. * * NOTE: The x,y coordinates should be relative to a coordinate system * with origin at the top left, as used by XImage and CGImage, not bottom * left as used by NSView. * * Side effects: * None * *---------------------------------------------------------------------- */ NSBitmapImageRep * TkMacOSXBitmapRepFromDrawableRect( Drawable drawable, int x, int y, unsigned int width, unsigned int height) { MacDrawable *mac_drawable = (MacDrawable *) drawable; CGContextRef cg_context = NULL; CGImageRef cg_image = NULL, sub_cg_image = NULL; NSBitmapImageRep *bitmap_rep = NULL; NSView *view = NULL; if (mac_drawable->flags & TK_IS_PIXMAP) { /* * This MacDrawable is a bitmap, so its view is NULL. */ CGRect image_rect = CGRectMake(x, y, width, height); cg_context = TkMacOSXGetCGContextForDrawable(drawable); cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context); sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect); if (sub_cg_image) { bitmap_rep = [NSBitmapImageRep alloc]; [bitmap_rep initWithCGImage:sub_cg_image]; } if (cg_image) { CGImageRelease(cg_image); } } else if ((view = TkMacOSXDrawableView(mac_drawable)) != NULL) { /* * Convert Tk top-left to NSView bottom-left coordinates. */ int view_height = [view bounds].size.height; NSRect view_rect = NSMakeRect(x + mac_drawable->xOff, view_height - height - y - mac_drawable->yOff, width, height); /* * Attempt to copy from the view to a bitmapImageRep. If the view does * not have a valid CGContext, doing this will silently corrupt memory * and make a big mess. So, in that case, we mark the view as needing * display and return NULL. */ |
︙ | ︙ | |||
214 215 216 217 218 219 220 | * * Copies data from one drawable to another. * * Results: * None. * * Side effects: | | < | | < > | > > > > | | | | | | | | | | | | | | | | | | | | | < < < < < | | | < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | * * Copies data from one drawable to another. * * Results: * None. * * Side effects: * Data is moved from a window or bitmap to a second window or bitmap. * *---------------------------------------------------------------------- */ void XCopyArea( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ GC gc, /* GC to use. */ int src_x, /* X & Y, width & height */ int src_y, /* define the source rectangle */ unsigned int width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y) { TkMacOSXDrawingContext dc; MacDrawable *srcDraw = (MacDrawable *) src; NSBitmapImageRep *bitmap_rep = NULL; CGImageRef img = NULL; CGRect bounds, srcRect, dstRect; display->request++; if (!width || !height) { return; } if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { TkMacOSXDbgMsg("Failed to setup drawing context."); return; } if (!dc.context) { TkMacOSXDbgMsg("Invalid destination drawable - no context."); return; } if (srcDraw->flags & TK_IS_PIXMAP) { img = TkMacOSXCreateCGImageWithDrawable(src); } else if (TkMacOSXDrawableWindow(src)) { bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src, src_x, src_y, width, height); if (bitmap_rep) { img = [bitmap_rep CGImage]; } } else { TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap."); } if (img) { bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height); srcRect = CGRectMake(src_x, src_y, width, height); dstRect = CGRectMake(dest_x, dest_y, width, height); TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background, bounds, srcRect, dstRect); CFRelease(img); } else { TkMacOSXDbgMsg("Failed to construct CGImage."); } TkMacOSXRestoreDrawingContext(&dc); } /* *---------------------------------------------------------------------- * * XCopyPlane -- * * Copies a bitmap from a source drawable to a destination drawable. The * plane argument specifies which bit plane of the source contains the * bitmap. Note that this implementation ignores the gc->function. * * Results: * None. * * Side effects: * Changes the destination drawable. * |
︙ | ︙ | |||
330 331 332 333 334 335 336 337 338 339 340 341 342 | if (plane != 1) { Tcl_Panic("Unexpected plane specified for XCopyPlane"); } if (srcDraw->flags & TK_IS_PIXMAP) { if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { return; } CGContextRef context = dc.context; if (context) { CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src); if (img) { TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; unsigned long imageBackground = gc->background; | > > > > | | > | > > > > | > > | > > > | > > > > | | > > | > | > | > | | > | > > > | > > | > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | if (plane != 1) { Tcl_Panic("Unexpected plane specified for XCopyPlane"); } if (srcDraw->flags & TK_IS_PIXMAP) { if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { return; } CGContextRef context = dc.context; if (context) { CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src); if (img) { TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; unsigned long imageBackground = gc->background; if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) { srcRect = CGRectMake(src_x, src_y, width, height); CGImageRef mask = TkMacOSXCreateCGImageWithDrawable( clipPtr->value.pixmap); CGImageRef submask = CGImageCreateWithImageInRect( img, srcRect); CGRect rect = CGRectMake(dest_x, dest_y, width, height); rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff); CGContextSaveGState(context); /* * Move the origin of the destination to top left. */ CGContextTranslateCTM(context, 0, rect.origin.y + CGRectGetMaxY(rect)); CGContextScaleCTM(context, 1, -1); /* * Fill with the background color, clipping to the mask. */ CGContextClipToMask(context, rect, submask); TkMacOSXSetColorInContext(gc, gc->background, dc.context); CGContextFillRect(context, rect); /* * Fill with the foreground color, clipping to the * intersection of img and mask. */ CGImageRef subimage = CGImageCreateWithImageInRect( img, srcRect); CGContextClipToMask(context, rect, subimage); TkMacOSXSetColorInContext(gc, gc->foreground, context); CGContextFillRect(context, rect); CGContextRestoreGState(context); CGImageRelease(img); CGImageRelease(mask); CGImageRelease(submask); CGImageRelease(subimage); } else { bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height); srcRect = CGRectMake(src_x, src_y, width, height); dstRect = CGRectMake(dest_x, dest_y, width, height); TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground, bounds, srcRect, dstRect); CGImageRelease(img); } } else { /* no image */ TkMacOSXDbgMsg("Invalid source drawable"); } } else { TkMacOSXDbgMsg("Invalid destination drawable - " "could not get a bitmap context."); } TkMacOSXRestoreDrawingContext(&dc); } else { /* * Source drawable is a Window, not a Pixmap. */ XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y); } } /* *---------------------------------------------------------------------- * * TkMacOSXCreateCGImageWithDrawable -- |
︙ | ︙ | |||
426 427 428 429 430 431 432 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | * * Side effects: * None. * *---------------------------------------------------------------------- */ static NSImage * CreateNSImageWithPixmap( Pixmap pixmap, int width, int height) { CGImageRef cgImage; NSImage *nsImage; |
︙ | ︙ | |||
462 463 464 465 466 467 468 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | * * Side effects: * None. * *---------------------------------------------------------------------- */ NSImage * TkMacOSXGetNSImageWithTkImage( Display *display, Tk_Image image, int width, int height) { Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0); |
︙ | ︙ | |||
495 496 497 498 499 500 501 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | * * Side effects: * None. * *---------------------------------------------------------------------- */ NSImage * TkMacOSXGetNSImageWithBitmap( Display *display, Pixmap bitmap, GC gc, int width, int height) { |
︙ | ︙ | |||
546 547 548 549 550 551 552 | if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) { const size_t bitsPerComponent = 8; size_t bitsPerPixel, bytesPerRow, len; CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ | | | | > | | | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) { const size_t bitsPerComponent = 8; size_t bitsPerPixel, bytesPerRow, len; CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ kCGBitmapByteOrder32Host; #else kCGBitmapByteOrderDefault; #endif char *data; CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height); if (macDraw->flags & TK_IS_BW_PIXMAP) { bitsPerPixel = 8; bitmapInfo = (CGBitmapInfo) kCGImageAlphaOnly; } else { colorspace = CGColorSpaceCreateDeviceRGB(); bitsPerPixel = 32; bitmapInfo |= kCGImageAlphaPremultipliedFirst; } bytesPerRow = ((size_t) macDraw->size.width * bitsPerPixel + 127) >> 3 & ~15; len = macDraw->size.height * bytesPerRow; data = ckalloc(len); bzero(data, len); macDraw->context = CGBitmapContextCreate(data, macDraw->size.width, macDraw->size.height, bitsPerComponent, bytesPerRow, colorspace, bitmapInfo); if (macDraw->context) { |
︙ | ︙ | |||
626 627 628 629 630 631 632 | if (subImage) { image = subImage; } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); if (CGImageIsMask(image)) { if (macDraw->flags & TK_IS_BW_PIXMAP) { | | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | if (subImage) { image = subImage; } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); if (CGImageIsMask(image)) { if (macDraw->flags & TK_IS_BW_PIXMAP) { /* * Set fill color to black; background comes from the context, * or is transparent. */ if (imageBackground != TRANSPARENT_PIXEL << 24) { CGContextClearRect(context, dstBounds); } CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0); |
︙ | ︙ | |||
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | #ifdef TK_MAC_DEBUG_IMAGE_DRAWING CGContextSaveGState(context); CGContextSetLineWidth(context, 1.0); CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.1); CGContextSetRGBFillColor(context, 0, 1, 0, 0.1); CGContextFillRect(context, dstBounds); CGContextStrokeRect(context, dstBounds); CGPoint p[4] = {dstBounds.origin, CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMaxY(dstBounds)), CGPointMake(CGRectGetMinX(dstBounds), CGRectGetMaxY(dstBounds)), CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMinY(dstBounds)) }; CGContextStrokeLineSegments(context, p, 4); CGContextRestoreGState(context); TkMacOSXDbgMsg("Drawing CGImage at (x=%f, y=%f), (w=%f, h=%f)", dstBounds.origin.x, dstBounds.origin.y, dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); | > > | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | #ifdef TK_MAC_DEBUG_IMAGE_DRAWING CGContextSaveGState(context); CGContextSetLineWidth(context, 1.0); CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.1); CGContextSetRGBFillColor(context, 0, 1, 0, 0.1); CGContextFillRect(context, dstBounds); CGContextStrokeRect(context, dstBounds); CGPoint p[4] = {dstBounds.origin, CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMaxY(dstBounds)), CGPointMake(CGRectGetMinX(dstBounds), CGRectGetMaxY(dstBounds)), CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMinY(dstBounds)) }; CGContextStrokeLineSegments(context, p, 4); CGContextRestoreGState(context); TkMacOSXDbgMsg("Drawing CGImage at (x=%f, y=%f), (w=%f, h=%f)", dstBounds.origin.x, dstBounds.origin.y, dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); |
︙ | ︙ | |||
732 733 734 735 736 737 738 739 | macWin->yOff + points[i].y + o); } else { prevx += points[i].x; prevy += points[i].y; CGContextAddLineToPoint(dc.context, prevx, prevy); } } /* | > | | | < > | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | macWin->yOff + points[i].y + o); } else { prevx += points[i].x; prevy += points[i].y; CGContextAddLineToPoint(dc.context, prevx, prevy); } } /* * In the case of closed polylines, the first and last points are the * same. We want miter or bevel join be rendered also at this point, * this needs telling CoreGraphics that the path is closed. */ if ((points[0].x == points[npoints-1].x) && (points[0].y == points[npoints-1].y)) { CGContextClosePath(dc.context); } CGContextStrokePath(dc.context); } TkMacOSXRestoreDrawingContext(&dc); |
︙ | ︙ | |||
816 817 818 819 820 821 822 | * Draws a filled polygon on the specified drawable. * *---------------------------------------------------------------------- */ void XFillPolygon( | | | | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | * Draws a filled polygon on the specified drawable. * *---------------------------------------------------------------------- */ void XFillPolygon( Display *display, /* Display. */ Drawable d, /* Draw on this. */ GC gc, /* Use this GC. */ XPoint *points, /* Array of points. */ int npoints, /* Number of points. */ int shape, /* Shape to draw. */ int mode) /* Drawing mode. */ { MacDrawable *macWin = (MacDrawable *) d; TkMacOSXDrawingContext dc; int i; |
︙ | ︙ | |||
898 899 900 901 902 903 904 | return; } if (dc.context) { CGRect rect; double o = (lw % 2) ? .5 : 0; rect = CGRectMake( | | < | | < | | | | < | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | return; } if (dc.context) { CGRect rect; double o = (lw % 2) ? .5 : 0; rect = CGRectMake( macWin->xOff + x + o, macWin->yOff + y + o, width, height); CGContextStrokeRect(dc.context, rect); } TkMacOSXRestoreDrawingContext(&dc); } #ifdef TK_MACOSXDRAW_UNUSED /* *---------------------------------------------------------------------- * * XDrawRectangles -- * * Draws the outlines of the specified rectangles as if a five-point * PolyLine protocol request were specified for each rectangle: * * [x,y] [x+width,y] [x+width,y+height] [x,y+height] [x,y] * * For the specified rectangles, these functions do not draw a pixel more * than once. XDrawRectangles draws the rectangles in the order listed in * the array. If rectangles intersect, the intersecting pixels are drawn * multiple times. Draws a rectangle. * * Results: * None. * * Side effects: * Draws rectangles on the specified drawable. * |
︙ | ︙ | |||
987 988 989 990 991 992 993 | * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ int XFillRectangles( | | | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 | * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ int XFillRectangles( Display *display, /* Display. */ Drawable d, /* Draw on this. */ GC gc, /* Use this GC. */ XRectangle *rectangles, /* Rectangle array. */ int n_rectangles) /* Number of rectangles. */ { MacDrawable *macWin = (MacDrawable *) d; TkMacOSXDrawingContext dc; |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | TkMacOSXRestoreDrawingContext(&dc); return Success; } /* *---------------------------------------------------------------------- * * XDrawArc -- * * Draw an arc. * * Results: * None. * * Side effects: * Draws an arc on the specified drawable. * *---------------------------------------------------------------------- */ void XDrawArc( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | TkMacOSXRestoreDrawingContext(&dc); return Success; } /* *---------------------------------------------------------------------- * * TkMacOSXDrawSolidBorder -- * * Draws a border rectangle of specified thickness inside the bounding * rectangle of a Tk Window. The border rectangle can be inset within the * bounding rectangle. For a highlight border the inset should be 0, but * for a solid border around the actual window the inset should equal the * thickness of the highlight border. The color of the border rectangle * is the foreground color of the graphics context passed to the function. * * Results: * None. * * Side effects: * Draws a rectangular border inside the bounding rectangle of a window. * *---------------------------------------------------------------------- */ MODULE_SCOPE void TkMacOSXDrawSolidBorder( Tk_Window tkwin, GC gc, int inset, int thickness) { Drawable d = Tk_WindowId(tkwin); TkMacOSXDrawingContext dc; CGRect outerRect, innerRect; if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { return; } if (dc.context) { outerRect = CGRectMake(Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin)); outerRect = CGRectInset(outerRect, inset, inset); innerRect = CGRectInset(outerRect, thickness, thickness); CGContextBeginPath(dc.context); CGContextAddRect(dc.context, outerRect); CGContextAddRect(dc.context, innerRect); CGContextEOFillPath(dc.context); } TkMacOSXRestoreDrawingContext(&dc); } /* *---------------------------------------------------------------------- * * XDrawArc -- * * Draw an arc. * * Results: * None. * * Side effects: * Draws an arc on the specified drawable. * *---------------------------------------------------------------------- */ void XDrawArc( Display *display, /* Display. */ Drawable d, /* Draw on this. */ GC gc, /* Use this GC. */ int x, int y, /* Upper left of bounding rect. */ unsigned int width, /* Width & height. */ unsigned int height, int angle1, /* Staring angle of arc. */ int angle2) /* Extent of arc. */ |
︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 | #ifdef TK_MACOSXDRAW_UNUSED /* *---------------------------------------------------------------------- * * XDrawArcs -- * | | | | < | | | | < | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | #ifdef TK_MACOSXDRAW_UNUSED /* *---------------------------------------------------------------------- * * XDrawArcs -- * * Draws multiple circular or elliptical arcs. Each arc is specified by a * rectangle and two angles. The center of the circle or ellipse is the * center of the rect- angle, and the major and minor axes are specified * by the width and height. Positive angles indicate counterclock- wise * motion, and negative angles indicate clockwise motion. If the magnitude * of angle2 is greater than 360 degrees, XDrawArcs truncates it to 360 * degrees. * * Results: * None. * * Side effects: * Draws an arc for each array element on the specified drawable. * *---------------------------------------------------------------------- */ void XDrawArcs( Display *display, Drawable d, GC gc, XArc *arcArr, int nArcs) { MacDrawable *macWin = (MacDrawable *) d; TkMacOSXDrawingContext dc; XArc *arcPtr; int i, lw = gc->line_width; display->request++; if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { |
︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 | * Draws a filled arc on the specified drawable. * *---------------------------------------------------------------------- */ void XFillArc( | | | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | * Draws a filled arc on the specified drawable. * *---------------------------------------------------------------------- */ void XFillArc( Display *display, /* Display. */ Drawable d, /* Draw on this. */ GC gc, /* Use this GC. */ int x, int y, /* Upper left of bounding rect. */ unsigned int width, /* Width & height. */ unsigned int height, int angle1, /* Staring angle of arc. */ int angle2) /* Extent of arc. */ |
︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 | #endif /* *---------------------------------------------------------------------- * * TkScrollWindow -- * | | | | | < | | > | > > | | > | > > | | | > | > > | > > | > > > | > > | 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 | #endif /* *---------------------------------------------------------------------- * * TkScrollWindow -- * * Scroll a rectangle of the specified window and accumulate a damage * region. * * Results: * Returns 0 if the scroll generated no additional damage. Otherwise, sets * the region that needs to be repainted after scrolling and returns 1. * * Side effects: * Scrolls the bits in the window. * *---------------------------------------------------------------------- */ int TkScrollWindow( Tk_Window tkwin, /* The window to be scrolled. */ GC gc, /* GC for window to be scrolled. */ int x, int y, /* Position rectangle to be scrolled. */ int width, int height, int dx, int dy, /* Distance rectangle should be moved. */ TkRegion damageRgn) /* Region to accumulate damage in. */ { Drawable drawable = Tk_WindowId(tkwin); MacDrawable *macDraw = (MacDrawable *) drawable; TKContentView *view = (TKContentView *) TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; int result = 0; if (view) { /* * Get the scroll area in NSView coordinates (origin at bottom left). */ bounds = [view bounds]; scrollSrc = NSMakeRect(macDraw->xOff + x, bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); /* * Limit scrolling to the window content area. */ visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); if (!NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst)) { /* * Mark the difference between source and destination as damaged. * This region is described in NSView coordinates (y=0 at the * bottom) and converted to Tk coordinates later. */ srcRect = CGRectMake(x, y, width, height); dstRect = CGRectOffset(srcRect, dx, dy); /* * Compute the damage. */ dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; /* * Convert to Tk coordinates, offset by the window origin. */ TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); if (extraRgn) { CFRelease(extraRgn); } /* * Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; } } else { dmgRgn = HIShapeCreateEmpty(); TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); } |
︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | *---------------------------------------------------------------------- * * TkMacOSXSetUpDrawingContext -- * * Set up a drawing context for the given drawable and GC. * * Results: | | | | | | | | | < > | > > | > | | | | | < | | | | | | | | | | | | | | | | < < < < | > > > | > > > | 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | *---------------------------------------------------------------------- * * TkMacOSXSetUpDrawingContext -- * * Set up a drawing context for the given drawable and GC. * * Results: * Boolean indicating whether it is ok to draw; if false, drawing context * was not setup, so do not attempt to draw and do not call * TkMacOSXRestoreDrawingContext(). * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool TkMacOSXSetupDrawingContext( Drawable d, GC gc, int useCG, /* advisory only ! */ TkMacOSXDrawingContext *dcPtr) { MacDrawable *macDraw = (MacDrawable *) d; Bool canDraw = true; NSWindow *win = NULL; TkMacOSXDrawingContext dc = {}; CGRect clipBounds; /* * If the drawable is not a pixmap and it has an associated NSWindow then * we know we are drawing to a window. */ if (!(macDraw->flags & TK_IS_PIXMAP)) { win = TkMacOSXDrawableWindow(d); } /* * Check that we have a non-empty clipping region. */ dc.clipRgn = TkMacOSXGetClipRgn(d); ClipToGC(d, gc, &dc.clipRgn); if (dc.clipRgn && HIShapeIsEmpty(dc.clipRgn)) { canDraw = false; goto end; } /* * If we already have a CGContext, use it. Otherwise, if we are drawing to * a window then we can get one from the window. */ dc.context = TkMacOSXGetCGContextForDrawable(d); if (dc.context) { dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context); } else if (win) { NSView *view = TkMacOSXDrawableView(macDraw); if (!view) { Tcl_Panic("TkMacOSXSetupDrawingContext(): " "no NSView to draw into !"); } /* * We can only draw into the view when the current CGContext is valid * and belongs to the view. Validity can only be guaranteed inside of * a view's drawRect or setFrame methods. The isDrawing attribute * tells us whether we are being called from one of those methods. * * If the CGContext is not valid, or belongs to a different View, then * we mark our view as needing display and return failure. It should * get drawn in a later call to drawRect. */ if (view != [NSView focusView]) { [view setNeedsDisplay:YES]; canDraw = false; goto end; } dc.view = view; dc.context = GET_CGCONTEXT; dc.portBounds = NSRectToCGRect([view bounds]); if (dc.clipRgn) { clipBounds = CGContextGetClipBoundingBox(dc.context); } } else { Tcl_Panic("TkMacOSXSetupDrawingContext(): " "no context to draw into !"); } /* * Configure the drawing context. */ if (dc.context) { CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = dc.portBounds.size.height }; dc.portBounds.origin.x += macDraw->xOff; dc.portBounds.origin.y += macDraw->yOff; CGContextSaveGState(dc.context); CGContextSetTextDrawingMode(dc.context, kCGTextFill); CGContextConcatCTM(dc.context, t); if (dc.clipRgn) { #ifdef TK_MAC_DEBUG_DRAWING CGContextSaveGState(dc.context); ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1); CGContextEOFillPath(dc.context); CGContextRestoreGState(dc.context); #endif /* TK_MAC_DEBUG_DRAWING */ CGRect r; if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( *HIShapeGetBounds(dc.clipRgn, &r), CGRectApplyAffineTransform(clipBounds, t))) { ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); CGContextEOClip(dc.context); } } |
︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 | double w = gc->line_width; TkMacOSXSetColorInContext(gc, gc->foreground, dc.context); if (win) { CGContextSetPatternPhase(dc.context, CGSizeMake( dc.portBounds.size.width, dc.portBounds.size.height)); } | | > > | > > > | > > | | | | > > | | > | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 | double w = gc->line_width; TkMacOSXSetColorInContext(gc, gc->foreground, dc.context); if (win) { CGContextSetPatternPhase(dc.context, CGSizeMake( dc.portBounds.size.width, dc.portBounds.size.height)); } if (gc->function != GXcopy) { TkMacOSXDbgMsg("Logical functions other than GXcopy are " "not supported for CG drawing!"); } /* * When should we antialias? */ shouldAntialias = !notAA(gc->line_width); if (!shouldAntialias) { /* * Make non-antialiased CG drawing look more like X11. */ w -= (gc->line_width ? NON_AA_CG_OFFSET : 0); } CGContextSetShouldAntialias(dc.context, shouldAntialias); CGContextSetLineWidth(dc.context, w); if (gc->line_style != LineSolid) { int num = 0; char *p = &gc->dashes; CGFloat dashOffset = gc->dash_offset; CGFloat lengths[10]; while (p[num] != '\0' && num < 10) { lengths[num] = p[num]; num++; } CGContextSetLineDash(dc.context, dashOffset, lengths, num); } if ((unsigned) gc->cap_style < sizeof(cgCap)/sizeof(CGLineCap)) { CGContextSetLineCap(dc.context, cgCap[(unsigned) gc->cap_style]); } if ((unsigned)gc->join_style < sizeof(cgJoin)/sizeof(CGLineJoin)) { CGContextSetLineJoin(dc.context, cgJoin[(unsigned) gc->join_style]); } } } end: #ifdef TK_MAC_DEBUG_DRAWING if (!canDraw && win != NULL) { TkWindow *winPtr = TkMacOSXGetTkWindow(win); if (winPtr) { fprintf(stderr, "Cannot draw in %s - postponing.\n", Tk_PathName(winPtr)); } } #endif if (!canDraw && dc.clipRgn) { CFRelease(dc.clipRgn); dc.clipRgn = NULL; } *dcPtr = dc; |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | MacDrawable *macDraw = (MacDrawable *) drawable; HIShapeRef clipRgn = NULL; if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(macDraw->winPtr); #ifdef TK_MAC_DEBUG_DRAWING TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName); NSView *view = TkMacOSXDrawableView(macDraw); CGContextSaveGState(context); CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, [view bounds].size.height)); ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context); CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1); CGContextEOFillPath(context); CGContextRestoreGState(context); | > > | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 | MacDrawable *macDraw = (MacDrawable *) drawable; HIShapeRef clipRgn = NULL; if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(macDraw->winPtr); #ifdef TK_MAC_DEBUG_DRAWING TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName); NSView *view = TkMacOSXDrawableView(macDraw); CGContextSaveGState(context); CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, [view bounds].size.height)); ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context); CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1); CGContextEOFillPath(context); CGContextRestoreGState(context); |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 | } /* *---------------------------------------------------------------------- * * TkMacOSXSetUpClippingRgn -- * | | | | 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 | } /* *---------------------------------------------------------------------- * * TkMacOSXSetUpClippingRgn -- * * Set up the clipping region so that drawing only occurs on the specified * X subwindow. * * Results: * None. * * Side effects: * None. * |
︙ | ︙ | |||
1762 1763 1764 1765 1766 1767 1768 | } /* *---------------------------------------------------------------------- * * TkpClipDrawableToRect -- * | | | | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 | } /* *---------------------------------------------------------------------- * * TkpClipDrawableToRect -- * * Clip all drawing into the drawable d to the given rectangle. If width * or height are negative, reset to no clipping. * * Results: * None. * * Side effects: * Subsequent drawing into d is offset and clipped as specified. * |
︙ | ︙ | |||
1828 1829 1830 1831 1832 1833 1834 | static void ClipToGC( Drawable d, GC gc, HIShapeRef *clipRgnPtr) /* must point to initialized variable */ { if (gc && gc->clip_mask && | | | | 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 | static void ClipToGC( Drawable d, GC gc, HIShapeRef *clipRgnPtr) /* must point to initialized variable */ { if (gc && gc->clip_mask && ((TkpClipMask *) gc->clip_mask)->type == TKP_CLIP_REGION) { TkRegion gcClip = ((TkpClipMask *) gc->clip_mask)->value.region; int xOffset = ((MacDrawable *) d)->xOff + gc->clip_x_origin; int yOffset = ((MacDrawable *) d)->yOff + gc->clip_y_origin; HIShapeRef clipRgn = *clipRgnPtr, gcClipRgn; TkMacOSXOffsetRegion(gcClip, xOffset, yOffset); gcClipRgn = TkMacOSXGetNativeRegion(gcClip); if (clipRgn) { |
︙ | ︙ | |||
1852 1853 1854 1855 1856 1857 1858 | } /* *---------------------------------------------------------------------- * * TkMacOSXMakeStippleMap -- * | | | | < | 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | } /* *---------------------------------------------------------------------- * * TkMacOSXMakeStippleMap -- * * Given a drawable and a stipple pattern this function draws the pattern * repeatedly over the drawable. The drawable can then be used as a mask * for bit-bliting a stipple pattern over an object. * * Results: * A BitMap data structure. * * Side effects: * None. * |
︙ | ︙ | |||
1879 1880 1881 1882 1883 1884 1885 | } /* *---------------------------------------------------------------------- * * TkpDrawHighlightBorder -- * | | | | | | | | | 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 | } /* *---------------------------------------------------------------------- * * TkpDrawHighlightBorder -- * * This procedure draws a rectangular ring around the outside of a widget * to indicate that it has received the input focus. * * On the Macintosh, this puts a 1 pixel border in the bgGC color between * the widget and the focus ring, except in the case where highlightWidth * is 1, in which case the border is left out. * * For proper Mac L&F, use highlightWidth of 3. * * Results: * None. * * Side effects: * A rectangle "width" pixels wide is drawn in "drawable", corresponding * to the outer area of "tkwin". * *---------------------------------------------------------------------- */ void TkpDrawHighlightBorder ( Tk_Window tkwin, |
︙ | ︙ | |||
1922 1923 1924 1925 1926 1927 1928 | } /* *---------------------------------------------------------------------- * * TkpDrawFrame -- * | | | | 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 | } /* *---------------------------------------------------------------------- * * TkpDrawFrame -- * * This procedure draws the rectangular frame area. If the user has * requested themeing, it draws with the background theme. * * Results: * None. * * Side effects: * Draws inside the tkwin area. * |
︙ | ︙ |
Changes to macosx/tkMacOSXEmbed.c.
︙ | ︙ | |||
330 331 332 333 334 335 336 | /* * Make a copy of the TK_EMBEDDED flag, since sometimes we need this to * get the port after the TkWindow structure has been freed. */ macWin->flags |= TK_EMBEDDED; macWin->xOff = parent->winPtr->privatePtr->xOff + | | | | | | | | | | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | /* * Make a copy of the TK_EMBEDDED flag, since sometimes we need this to * get the port after the TkWindow structure has been freed. */ macWin->flags |= TK_EMBEDDED; macWin->xOff = parent->winPtr->privatePtr->xOff + parent->winPtr->changes.border_width + winPtr->changes.x; macWin->yOff = parent->winPtr->privatePtr->yOff + parent->winPtr->changes.border_width + winPtr->changes.y; /* * Finish filling up the container structure with the embedded window's * information. */ containerPtr->embedded = (Window) macWin; containerPtr->embeddedPtr = macWin->winPtr; /* * Create an event handler to clean up the Container structure when * tkwin is eventually deleted. */ Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, winPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
584 585 586 587 588 589 590 | if (containerPtr->parentPtr != NULL) { parentInterp = containerPtr->parentPtr->mainPtr->interp; } if (embeddedInterp != interp && parentInterp != interp) { continue; } Tcl_DStringStartSublist(&dString); | > > | > > | > > > | > > > > > > | > > | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | if (containerPtr->parentPtr != NULL) { parentInterp = containerPtr->parentPtr->mainPtr->interp; } if (embeddedInterp != interp && parentInterp != interp) { continue; } Tcl_DStringStartSublist(&dString); /* * Parent id */ if (containerPtr->parent == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { sprintf(buffer, "0x%" TCL_Z_MODIFIER "x", (size_t) containerPtr->parent); Tcl_DStringAppendElement(&dString, buffer); } else { Tcl_DStringAppendElement(&dString, "XXX"); } /* * Parent pathName */ if (containerPtr->parentPtr == NULL || parentInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, containerPtr->parentPtr->pathName); } /* * On X11 embedded is a wrapper, which does not exist on macOS. */ Tcl_DStringAppendElement(&dString, ""); /* * Embedded window pathName */ if (containerPtr->embeddedPtr == NULL || embeddedInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, containerPtr->embeddedPtr->pathName); } |
︙ | ︙ | |||
764 765 766 767 768 769 770 771 772 773 774 775 776 777 | Container *containerPtr; Tk_ErrorHandler errHandler; if (!firstContainerPtr) { /* * When the interpreter is being dismantled this can be nil. */ return; } /* * Ignore any X protocol errors that happen in this procedure (almost any * operation could fail, for example, if the embedded application has * deleted its window). | > | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | Container *containerPtr; Tk_ErrorHandler errHandler; if (!firstContainerPtr) { /* * When the interpreter is being dismantled this can be nil. */ return; } /* * Ignore any X protocol errors that happen in this procedure (almost any * operation could fail, for example, if the embedded application has * deleted its window). |
︙ | ︙ | |||
916 917 918 919 920 921 922 923 924 925 926 927 928 929 | static void EmbedActivateProc( ClientData clientData, /* Token for container window. */ XEvent *eventPtr) /* ResizeRequest event. */ { Container *containerPtr = clientData; if (containerPtr->embeddedPtr != NULL) { if (eventPtr->type == ActivateNotify) { TkGenerateActivateEvents(containerPtr->embeddedPtr,1); } else if (eventPtr->type == DeactivateNotify) { TkGenerateActivateEvents(containerPtr->embeddedPtr,0); } } | > | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | static void EmbedActivateProc( ClientData clientData, /* Token for container window. */ XEvent *eventPtr) /* ResizeRequest event. */ { Container *containerPtr = clientData; if (containerPtr->embeddedPtr != NULL) { if (eventPtr->type == ActivateNotify) { TkGenerateActivateEvents(containerPtr->embeddedPtr,1); } else if (eventPtr->type == DeactivateNotify) { TkGenerateActivateEvents(containerPtr->embeddedPtr,0); } } |
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 | int width, int height) /* Size that the child has requested. */ { TkWindow *winPtr = containerPtr->parentPtr; /* * Forward the requested size into our geometry management hierarchy via * the container window. We need to send a Configure event back to the | | | | | < | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | int width, int height) /* Size that the child has requested. */ { TkWindow *winPtr = containerPtr->parentPtr; /* * Forward the requested size into our geometry management hierarchy via * the container window. We need to send a Configure event back to the * embedded application if we decide not to honor its request; to make this * happen, process all idle event handlers synchronously here (so that the * geometry managers have had a chance to do whatever they want to do), and * if the window's size didn't change then generate a configure event. */ Tk_GeometryRequest((Tk_Window) winPtr, width, height); while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) { /* Empty loop body. */ } if ((winPtr->changes.width != width) |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 | * * EmbedSendConfigure -- * * This is currently a stub. It is called to notify an embedded * application of its current size and location. This procedure is called * when the embedded application made a geometry request that we did not * grant, so that the embedded application knows that its geometry didn't | | | | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 | * * EmbedSendConfigure -- * * This is currently a stub. It is called to notify an embedded * application of its current size and location. This procedure is called * when the embedded application made a geometry request that we did not * grant, so that the embedded application knows that its geometry didn't * change after all. It is a response to ConfigureRequest events, which we * do not currently synthesize on the Mac * * Results: * None. * * Side effects: * None. * |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | * Fabricate an event to do this. */ if (containerPtr->parentPtr != NULL && containerPtr->parentPtr->flags & TK_BOTH_HALVES) { XEvent event; | | | | 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 | * Fabricate an event to do this. */ if (containerPtr->parentPtr != NULL && containerPtr->parentPtr->flags & TK_BOTH_HALVES) { XEvent event; event.xany.serial = LastKnownRequestProcessed( Tk_Display(containerPtr->parentPtr)); event.xany.send_event = False; event.xany.display = Tk_Display(containerPtr->parentPtr); event.xany.type = DestroyNotify; event.xany.window = containerPtr->parent; event.xdestroywindow.event = containerPtr->parent; Tk_QueueWindowEvent(&event, TCL_QUEUE_HEAD); |
︙ | ︙ |
Changes to macosx/tkMacOSXFont.c.
1 2 3 | /* * tkMacOSXFont.c -- * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 | /* * tkMacOSXFont.c -- * * Contains the Macintosh implementation of the platform-independant font * package interface. * * Copyright 2002-2004 Benjamin Riefenstahl, [email protected] * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright 2008-2009, Apple Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
︙ | ︙ | |||
28 29 30 31 32 33 34 | /* * The following structure represents our Macintosh-specific implementation * of a font object. */ typedef struct { | | | < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* * The following structure represents our Macintosh-specific implementation * of a font object. */ typedef struct { TkFont font; /* Stuff used by generic font package. Must be * first in structure. */ NSFont *nsFont; NSDictionary *nsAttributes; } MacFont; /* * The names for our "native" fonts. */ |
︙ | ︙ | |||
79 80 81 82 83 84 85 | }; #undef ThemeFont static int antialiasedTextEnabled = -1; static NSCharacterSet *whitespaceCharacterSet = nil; static NSCharacterSet *lineendingCharacterSet = nil; | | | | > | > | | | > | | | > | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | }; #undef ThemeFont static int antialiasedTextEnabled = -1; static NSCharacterSet *whitespaceCharacterSet = nil; static NSCharacterSet *lineendingCharacterSet = nil; static void GetTkFontAttributesForNSFont(NSFont *nsFont, TkFontAttributes *faPtr); static NSFont * FindNSFont(const char *familyName, NSFontTraitMask traits, NSInteger weight, CGFloat size, int fallbackToDefault); static void InitFont(NSFont *nsFont, const TkFontAttributes *reqFaPtr, MacFont *fontPtr); static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin, const char *name, TkFontAttributes *faPtr); static void DrawCharsInContext(Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, int rangeStart, int rangeLength, int x, int y, double angle); #pragma mark - #pragma mark Font Helpers: #define GetNSFontTraitsFromTkFontAttributes(faPtr) \ ((faPtr)->weight == TK_FW_BOLD ? NSBoldFontMask : NSUnboldFontMask) | \ ((faPtr)->slant == TK_FS_ITALIC ? NSItalicFontMask : NSUnitalicFontMask) |
︙ | ︙ | |||
228 229 230 231 232 233 234 | NSDictionary *nsAttributes; NSRect bounds; CGFloat kern = 0.0; NSFontRenderingMode renderingMode = NSFontDefaultRenderingMode; int ascent, descent/*, dontAA*/; static const UniChar ch[] = {'.', 'W', ' ', 0xc4, 0xc1, 0xc2, 0xc3, 0xc7}; /* ., W, Space, Auml, Aacute, Acirc, Atilde, Ccedilla */ | | > > | > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | NSDictionary *nsAttributes; NSRect bounds; CGFloat kern = 0.0; NSFontRenderingMode renderingMode = NSFontDefaultRenderingMode; int ascent, descent/*, dontAA*/; static const UniChar ch[] = {'.', 'W', ' ', 0xc4, 0xc1, 0xc2, 0xc3, 0xc7}; /* ., W, Space, Auml, Aacute, Acirc, Atilde, Ccedilla */ #define nCh (sizeof(ch) / sizeof(UniChar)) CGGlyph glyphs[nCh]; CGRect boundingRects[nCh]; fontPtr->font.fid = (Font) fontPtr; faPtr = &fontPtr->font.fa; if (reqFaPtr) { *faPtr = *reqFaPtr; } else { TkInitFontAttributes(faPtr); } fontPtr->nsFont = nsFont; /* * Some don't like antialiasing on fixed-width even if bigger than limit */ // dontAA = [nsFont isFixedPitch] && fontPtr->font.fa.size <= 10; if (antialiasedTextEnabled >= 0/* || dontAA*/) { renderingMode = (antialiasedTextEnabled == 0/* || dontAA*/) ? NSFontIntegerAdvancementsRenderingMode : NSFontAntialiasedRenderingMode; } nsFont = [nsFont screenFontWithRenderingMode:renderingMode]; |
︙ | ︙ | |||
290 291 292 293 294 295 296 | [NSNumber numberWithInt:faPtr->overstrike ? NSUnderlineStyleSingle|NSUnderlinePatternSolid : NSUnderlineStyleNone], NSStrikethroughStyleAttributeName, [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1], NSLigatureAttributeName, [NSNumber numberWithDouble:kern], NSKernAttributeName, nil]; fontPtr->nsAttributes = [nsAttributes retain]; | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | [NSNumber numberWithInt:faPtr->overstrike ? NSUnderlineStyleSingle|NSUnderlinePatternSolid : NSUnderlineStyleNone], NSStrikethroughStyleAttributeName, [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1], NSLigatureAttributeName, [NSNumber numberWithDouble:kern], NSKernAttributeName, nil]; fontPtr->nsAttributes = [nsAttributes retain]; #undef nCh } /* *------------------------------------------------------------------------- * * CreateNamedSystemFont -- * |
︙ | ︙ | |||
354 355 356 357 358 359 360 | { Tcl_Interp *interp = mainPtr->interp; Tk_Window tkwin = (Tk_Window) mainPtr->winPtr; const struct SystemFontMapEntry *systemFont = systemFontMap; NSFont *nsFont; TkFontAttributes fa; NSMutableCharacterSet *cs; | > | > > | > | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | { Tcl_Interp *interp = mainPtr->interp; Tk_Window tkwin = (Tk_Window) mainPtr->winPtr; const struct SystemFontMapEntry *systemFont = systemFontMap; NSFont *nsFont; TkFontAttributes fa; NSMutableCharacterSet *cs; /* * Since we called before TkpInit, we need our own autorelease pool. */ NSAutoreleasePool *pool = [NSAutoreleasePool new]; /* * Force this for now. */ if (!mainPtr->winPtr->mainPtr) { mainPtr->winPtr->mainPtr = mainPtr; } while (systemFont->systemName) { nsFont = (NSFont*) CTFontCreateUIFontForLanguage( HIThemeGetUIFontType(systemFont->id), 0, NULL); if (nsFont) { |
︙ | ︙ | |||
409 410 411 412 413 414 415 | *--------------------------------------------------------------------------- * * TkpGetNativeFont -- * * Map a platform-specific native font name to a TkFont. * * Results: | | | | | | | | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | *--------------------------------------------------------------------------- * * TkpGetNativeFont -- * * Map a platform-specific native font name to a TkFont. * * Results: * The return value is a pointer to a TkFont that represents the native * font. If a native font by the given name could not be found, the return * value is NULL. * * Every call to this procedure returns a new TkFont structure, even if * the name has already been seen before. The caller should call * TkpDeleteFont() when the font is no longer needed. * * The caller is responsible for initializing the memory associated with * the generic TkFont when this function returns and releasing the * contents of the generics TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */ |
︙ | ︙ | |||
445 446 447 448 449 450 451 | } else if (strcmp(name, APPLFONT_NAME) == 0) { themeFontId = kThemeApplicationFont; } else if (strcmp(name, MENUITEMFONT_NAME) == 0) { themeFontId = kThemeMenuItemFont; } else { return NULL; } | | | | | | < | | | | | | | | | | | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | } else if (strcmp(name, APPLFONT_NAME) == 0) { themeFontId = kThemeApplicationFont; } else if (strcmp(name, MENUITEMFONT_NAME) == 0) { themeFontId = kThemeMenuItemFont; } else { return NULL; } ctFont = CTFontCreateUIFontForLanguage( HIThemeGetUIFontType(themeFontId), 0, NULL); if (ctFont) { fontPtr = ckalloc(sizeof(MacFont)); InitFont((NSFont*) ctFont, NULL, fontPtr); } return (TkFont *) fontPtr; } /* *--------------------------------------------------------------------------- * * TkpGetFontFromAttributes -- * * Given a desired set of attributes for a font, find a font with the * closest matching attributes. * * Results: * The return value is a pointer to a TkFont that represents the font with * the desired attributes. If a font with the desired attributes could not * be constructed, some other font will be substituted automatically. * * Every call to this procedure returns a new TkFont structure, even if * the specified attributes have already been seen before. The caller * should call TkpDeleteFont() to free the platform- specific data when * the font is no longer needed. * * The caller is responsible for initializing the memory associated with * the generic TkFont when this function returns and releasing the * contents of the generic TkFont before calling TkpDeleteFont(). * * Side effects: * None. * *--------------------------------------------------------------------------- */ TkFont * TkpGetFontFromAttributes( TkFont *tkFontPtr, /* If non-NULL, store the information in this * existing TkFont structure, rather than * allocating a new structure to hold the font; * the existing contents of the font will be * released. If NULL, a new TkFont structure is * allocated. */ Tk_Window tkwin, /* For display where font will be used. */ const TkFontAttributes *faPtr) /* Set of attributes to match. */ { MacFont *fontPtr; int points = (int) (TkFontGetPoints(tkwin, faPtr->size) + 0.5); NSFontTraitMask traits = GetNSFontTraitsFromTkFontAttributes(faPtr); NSInteger weight = (faPtr->weight == TK_FW_BOLD ? 9 : 5); NSFont *nsFont; nsFont = FindNSFont(faPtr->family, traits, weight, points, 0); if (!nsFont) { const char *const *aliases = TkFontGetAliasList(faPtr->family); |
︙ | ︙ | |||
534 535 536 537 538 539 540 | /* *--------------------------------------------------------------------------- * * TkpDeleteFont -- * * Called to release a font allocated by TkpGetNativeFont() or | | | | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | /* *--------------------------------------------------------------------------- * * TkpDeleteFont -- * * Called to release a font allocated by TkpGetNativeFont() or * TkpGetFontFromAttributes(). The caller should have already released the * fields of the TkFont that are used exclusively by the generic TkFont * code. * * Results: * TkFont is deallocated. * * Side effects: * None. * |
︙ | ︙ | |||
563 564 565 566 567 568 569 | } /* *--------------------------------------------------------------------------- * * TkpGetFontFamilies -- * | | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | } /* *--------------------------------------------------------------------------- * * TkpGetFontFamilies -- * * Return information about the font families that are available on the * display of the given window. * * Results: * Modifies interp's result object to hold a list of all the available * font families. * * Side effects: * None. |
︙ | ︙ | |||
596 597 598 599 600 601 602 | } /* *------------------------------------------------------------------------- * * TkpGetSubFonts -- * | | | | | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | } /* *------------------------------------------------------------------------- * * TkpGetSubFonts -- * * A function used by the testing package for querying the actual screen * fonts that make up a font object. * * Results: * Modifies interp's result object to hold a list containing the names of * the screen fonts that make up the given font object. * * Side effects: * None. * *------------------------------------------------------------------------- */ |
︙ | ︙ | |||
638 639 640 641 642 643 644 | } /* *---------------------------------------------------------------------- * * TkpGetFontAttrsForChar -- * | | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | } /* *---------------------------------------------------------------------- * * TkpGetFontAttrsForChar -- * * Retrieve the font attributes of the actual font used to render a given * character. * * Results: * None. * * Side effects: * The font attributes are stored in *faPtr. * |
︙ | ︙ | |||
741 742 743 744 745 746 747 | * that TkpDrawCharsInContext() will be used to actually display the * characters. * * This one is almost the same as Tk_MeasureChars(), but with access to * all the characters on the line for context. * * Results: | | | | < | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | * that TkpDrawCharsInContext() will be used to actually display the * characters. * * This one is almost the same as Tk_MeasureChars(), but with access to * all the characters on the line for context. * * Results: * The return value is the number of bytes from source that fit into the * span that extends from 0 to maxLength. *lengthPtr is filled with the * x-coordinate of the right edge of the last character that did fit. * * Side effects: * None. * *--------------------------------------------------------------------------- */ |
︙ | ︙ | |||
770 771 772 773 774 775 776 | * character that would cross this x-position. * If < 0, then line length is unbounded and * the flags argument is ignored. */ int flags, /* Various flag bits OR-ed together: * TK_PARTIAL_OK means include the last char * which only partially fits on this line. * TK_WHOLE_WORDS means stop on a word | | | | | | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | * character that would cross this x-position. * If < 0, then line length is unbounded and * the flags argument is ignored. */ int flags, /* Various flag bits OR-ed together: * TK_PARTIAL_OK means include the last char * which only partially fits on this line. * TK_WHOLE_WORDS means stop on a word * boundary, if possible. TK_AT_LEAST_ONE means * return at least one character even if no * characters fit. If TK_WHOLE_WORDS and * TK_AT_LEAST_ONE are set and the first word * doesn't fit, we return at least one * character or whatever characters fit into * maxLength. TK_ISOLATE_END means that the * last character should not be considered in * context with the rest of the string (used * for breaking lines). */ int *lengthPtr) /* Filled with x-location just after the * terminating character. */ |
︙ | ︙ | |||
860 861 862 863 864 865 866 | whitespaceCharacterSet : lineendingCharacterSet; while (index > start && [cs characterIsMember:[string characterAtIndex:(index - 1)]]) { index--; } /* | | | | | | | < | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | whitespaceCharacterSet : lineendingCharacterSet; while (index > start && [cs characterIsMember:[string characterAtIndex:(index - 1)]]) { index--; } /* * If there is no line breakpoint in the source string between its * start and the index position that fits in maxWidth, then * CTTypesetterSuggestLineBreak() returns that very last index. * However if the TK_WHOLE_WORDS flag is set, we want to break at a * word boundary. In this situation, unless TK_AT_LEAST_ONE is set, we * must report that zero chars actually fit (in other words the * smallest word of the source string is still larger than maxWidth). */ if ((index >= start) && (index < len) && (flags & TK_WHOLE_WORDS) && !(flags & TK_AT_LEAST_ONE) && ![cs characterIsMember:[string characterAtIndex:index]]) { index = start; } |
︙ | ︙ | |||
899 900 901 902 903 904 905 | if (width < maxWidth && (flags & TK_PARTIAL_OK) && index < len) { range.length = ++index; line = CTTypesetterCreateLine(typesetter, range); width = CTLineGetTypographicBounds(line, NULL, NULL, NULL); CFRelease(line); } | > | | | > > | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | if (width < maxWidth && (flags & TK_PARTIAL_OK) && index < len) { range.length = ++index; line = CTTypesetterCreateLine(typesetter, range); width = CTLineGetTypographicBounds(line, NULL, NULL, NULL); CFRelease(line); } /* * The call to CTTypesetterSuggestClusterBreak above will always return * at least one character regardless of whether it exceeded it or not. * Clean that up now. */ while (width > maxWidth && !(flags & TK_PARTIAL_OK) && index > start+(flags & TK_AT_LEAST_ONE)) { range.length = --index; line = CTTypesetterCreateLine(typesetter, range); width = CTLineGetTypographicBounds(line, NULL, NULL, NULL); CFRelease(line); } |
︙ | ︙ | |||
942 943 944 945 946 947 948 | * * Draw a string of characters on the screen. * * With ATSUI we need the line context to do this right, so we have the * actual implementation in TkpDrawCharsInContext(). * * Results: | | | | | | | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | * * Draw a string of characters on the screen. * * With ATSUI we need the line context to do this right, so we have the * actual implementation in TkpDrawCharsInContext(). * * Results: * None. * * Side effects: * Information gets drawn on the screen. * *--------------------------------------------------------------------------- */ void Tk_DrawChars( Display *display, /* Display on which to draw. */ Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; must * be the same as font used in GC. */ const char *source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that is * passed to this function. If they are not * stripped out, they will be displayed as * regular printing characters. */ int numBytes, /* Number of bytes in string. */ int x, int y) /* Coordinates at which to place origin of the * string when drawing. */ { DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, 0, numBytes, x, y, 0.0); } void TkDrawAngledChars( Display *display, /* Display on which to draw. */ Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; * must be the same as font used in GC. */ const char *source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that is * passed to this function. If they are not * stripped out, they will be displayed as * regular printing characters. */ int numBytes, /* Number of bytes in string. */ double x, double y, /* Coordinates at which to place origin of * string when drawing. */ double angle) /* What angle to put text at, in degrees. */ { |
︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 | Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; must * be the same as font used in GC. */ const char * source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) | | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; must * be the same as font used in GC. */ const char * source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that is * passed to this function. If they are not * stripped out, they will be displayed as * regular printing characters. */ int numBytes, /* Number of bytes in string. */ int rangeStart, /* Index of first byte to draw. */ int rangeLength, /* Length of range to draw in bytes. */ int x, int y) /* Coordinates at which to place origin of the * whole (not just the range) string when |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 | Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; must * be the same as font used in GC. */ const char * source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) | | | | 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; must * be the same as font used in GC. */ const char * source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that is * passed to this function. If they are not * stripped out, they will be displayed as * regular printing characters. */ int numBytes, /* Number of bytes in string. */ int rangeStart, /* Index of first byte to draw. */ int rangeLength, /* Length of range to draw in bytes. */ int x, int y, /* Coordinates at which to place origin of the * whole (not just the range) string when |
︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | return; } string = [[NSString alloc] initWithBytesNoCopy:(void*)source length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO]; if (!string) { return; } context = drawingContext.context; fg = TkMacOSXCreateCGColor(gc, gc->foreground); attributes = [fontPtr->nsAttributes mutableCopy]; [attributes setObject:(id)fg forKey:(id)kCTForegroundColorAttributeName]; CFRelease(fg); nsFont = [attributes objectForKey:NSFontAttributeName]; [nsFont setInContext:[NSGraphicsContext graphicsContextWithGraphicsPort: | > | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 | return; } string = [[NSString alloc] initWithBytesNoCopy:(void*)source length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO]; if (!string) { return; } context = drawingContext.context; fg = TkMacOSXCreateCGColor(gc, gc->foreground); attributes = [fontPtr->nsAttributes mutableCopy]; [attributes setObject:(id)fg forKey:(id)kCTForegroundColorAttributeName]; CFRelease(fg); nsFont = [attributes objectForKey:NSFontAttributeName]; [nsFont setInContext:[NSGraphicsContext graphicsContextWithGraphicsPort: |
︙ | ︙ | |||
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | } CGContextConcatCTM(context, t); CGContextSetTextPosition(context, x, y); start = Tcl_NumUtfChars(source, rangeStart); len = Tcl_NumUtfChars(source, rangeStart + rangeLength); if (start > 0) { CGRect clipRect = CGRectInfinite, startBounds; line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start)); startBounds = CTLineGetImageBounds(line, context); CFRelease(line); clipRect.origin.x = startBounds.origin.x + startBounds.size.width; CGContextClipToRect(context, clipRect); } line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, len)); | > | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | } CGContextConcatCTM(context, t); CGContextSetTextPosition(context, x, y); start = Tcl_NumUtfChars(source, rangeStart); len = Tcl_NumUtfChars(source, rangeStart + rangeLength); if (start > 0) { CGRect clipRect = CGRectInfinite, startBounds; line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start)); startBounds = CTLineGetImageBounds(line, context); CFRelease(line); clipRect.origin.x = startBounds.origin.x + startBounds.size.width; CGContextClipToRect(context, clipRect); } line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, len)); |
︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 1244 1245 | if (nsFont && familyName) { NSFontTraitMask traits = [[NSFontManager sharedFontManager] traitsOfFont:nsFont]; id underline = [nsAttributes objectForKey: NSUnderlineStyleAttributeName]; id strikethrough = [nsAttributes objectForKey: NSStrikethroughStyleAttributeName]; objv[i++] = Tcl_NewStringObj(familyName, -1); objv[i++] = Tcl_NewWideIntObj([nsFont pointSize]); | > | | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | if (nsFont && familyName) { NSFontTraitMask traits = [[NSFontManager sharedFontManager] traitsOfFont:nsFont]; id underline = [nsAttributes objectForKey: NSUnderlineStyleAttributeName]; id strikethrough = [nsAttributes objectForKey: NSStrikethroughStyleAttributeName]; objv[i++] = Tcl_NewStringObj(familyName, -1); objv[i++] = Tcl_NewWideIntObj([nsFont pointSize]); #define S(s) Tcl_NewStringObj(STRINGIFY(s), (int)(sizeof(STRINGIFY(s))-1)) objv[i++] = (traits & NSBoldFontMask) ? S(bold) : S(normal); objv[i++] = (traits & NSItalicFontMask) ? S(italic) : S(roman); if ([underline respondsToSelector:@selector(intValue)] && ([underline intValue] & (NSUnderlineStyleSingle | NSUnderlineStyleThick | NSUnderlineStyleDouble))) { objv[i++] = S(underline); } |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | /* *---------------------------------------------------------------------- * * TkMacOSXUseAntialiasedText -- * * Enables or disables application-wide use of antialiased text (where | | | > | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | /* *---------------------------------------------------------------------- * * TkMacOSXUseAntialiasedText -- * * Enables or disables application-wide use of antialiased text (where * available). Sets up a linked Tcl global variable to allow disabling of * antialiased text from Tcl. * * The possible values for this variable are: * * -1 - Use system default as configurable in "System Prefs" -> "General". * 0 - Unconditionally disable antialiasing. * 1 - Unconditionally enable antialiasing. * * Results: |
︙ | ︙ |
Changes to macosx/tkMacOSXHLEvents.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | * AppleEvent */ } KillEvent; /* * Static functions used only in this file. */ | | | | < | | > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | * AppleEvent */ } KillEvent; /* * Static functions used only in this file. */ static void tkMacOSXProcessFiles(NSAppleEventDescriptor *event, NSAppleEventDescriptor *replyEvent, Tcl_Interp *interp, const char* procedure); static int MissedAnyParameters(const AppleEvent *theEvent); static int ReallyKillMe(Tcl_Event *eventPtr, int flags); static void RunSimpleTclCommand(Tcl_Interp *interp, const char *command); #pragma mark TKApplication(TKHLEvents) @implementation TKApplication(TKHLEvents) - (void) terminate: (id) sender { [self handleQuitApplicationEvent:Nil withReplyEvent:Nil]; |
︙ | ︙ | |||
74 75 76 77 78 79 80 | Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD); } } - (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { | < < < | < < < < < < < < | < < < < < < | < < < < < < | > | > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD); } } - (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { RunSimpleTclCommand(_eventInterp, "::tk::mac::OpenApplication"); } - (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { [NSApp activateIgnoringOtherApps: YES]; RunSimpleTclCommand(_eventInterp, "::tk::mac::ReopenApplication"); } - (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { RunSimpleTclCommand(_eventInterp, "::tk::mac::ShowPreferences"); } - (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument"); } - (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::PrintDocument"); } - (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { OSStatus err; const AEDesc *theDesc = nil; |
︙ | ︙ | |||
148 149 150 151 152 153 154 | theDesc = [event aeDesc]; if (theDesc == nil) { return; } err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType, | | | | | | | > > | > | | | | > > | | | > > | > | | > | | > > | > | | | | | | > | > > > > > > > > > > > > > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | theDesc = [event aeDesc]; if (theDesc == nil) { return; } err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType, NULL, 0, NULL); if (err != noErr) { sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err); AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString, typeChar, errString, strlen(errString)); return; } if (MissedAnyParameters((AppleEvent *) theDesc)) { sprintf(errString, "AEDoScriptHandler: extra parameters"); AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString, typeChar, errString, strlen(errString)); return; } Tcl_Preserve(_eventInterp); if (initialType == typeFileURL || initialType == typeAlias) { /* * The descriptor can be coerced to a file url. Source the file, or * pass the path as a string argument to ::tk::mac::DoScriptFile if * that procedure exists. */ err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type, (Ptr) URLBuffer, URL_MAX_LENGTH, &actual); if (err == noErr && actual > 0){ URLBuffer[actual] = '\0'; NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer]; NSURL *fileURL = [NSURL URLWithString:urlString]; Tcl_DString command; Tcl_DStringInit(&command); if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)) { Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1); } else { Tcl_DStringAppend(&command, "source", -1); } Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]); tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); } } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type, NULL, 0, &actual)) { if (actual > 0) { /* * The descriptor can be coerced to UTF8 text. Evaluate as Tcl, or * or pass the text as a string argument to ::tk::mac::DoScriptText * if that procedure exists. */ char *data = ckalloc(actual + 1); if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type, data, actual, NULL)) { if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)) { Tcl_DString command; Tcl_DStringInit(&command); Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1); Tcl_DStringAppendElement(&command, data); tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); } else { tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL); } } ckfree(data); } } else { /* * The descriptor can not be coerced to a fileURL or UTF8 text. */ for (int i = 0; i < 4; i++) { typeString[i] = ((char*)&initialType)[3-i]; } typeString[4] = '\0'; sprintf(errString, "AEDoScriptHandler: invalid script type '%s', " "must be coercable to 'furl' or 'utf8'", typeString); AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString, strlen(errString)); } /* * If we ran some Tcl code, put the result in the reply. */ if (tclErr >= 0) { int reslen; const char *result = Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen); if (tclErr == TCL_OK) { AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyDirectObject, typeChar, result, reslen); } else { AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString, typeChar, result, reslen); AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorNumber, typeSInt32, (Ptr) &tclErr, sizeof(int)); } } Tcl_Release(_eventInterp); return; } @end #pragma mark - static void RunSimpleTclCommand( Tcl_Interp *interp, const char *command) { int code; if (interp && Tcl_FindCommand(interp, command, NULL, 0)) { Tcl_Preserve(interp); code = Tcl_EvalEx(interp, command, -1, TCL_EVAL_GLOBAL); if (code != TCL_OK) { Tcl_BackgroundException(interp, code); } Tcl_Release(interp); } } /* *---------------------------------------------------------------------- * * TkMacOSXProcessFiles -- * * Extract a list of fileURLs from an AppleEvent and call the specified * procedure with the file paths as arguments. |
︙ | ︙ | |||
283 284 285 286 287 288 289 | Size actual; long count, index; AEKeyword keyword; Tcl_DString command, pathName; int code; /* | | > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | Size actual; long count, index; AEKeyword keyword; Tcl_DString command, pathName; int code; /* * Do nothing if we don't have an interpreter or the procedure doesn't * exist. */ if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) { return; } fileSpecDesc = [event aeDesc]; |
︙ | ︙ | |||
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | Tcl_FreeEncoding(utf8); AEDisposeDesc(&contents); /* * Handle the event by evaluating the Tcl expression we constructed. */ code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); if (code != TCL_OK) { Tcl_BackgroundException(interp, code); } Tcl_DStringFree(&command); } /* *---------------------------------------------------------------------- * * TkMacOSXInitAppleEvents -- * | > > | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | Tcl_FreeEncoding(utf8); AEDisposeDesc(&contents); /* * Handle the event by evaluating the Tcl expression we constructed. */ Tcl_Preserve(interp); code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); if (code != TCL_OK) { Tcl_BackgroundException(interp, code); } Tcl_DStringFree(&command); Tcl_Release(interp); } /* *---------------------------------------------------------------------- * * TkMacOSXInitAppleEvents -- * |
︙ | ︙ | |||
378 379 380 381 382 383 384 | *---------------------------------------------------------------------- */ void TkMacOSXInitAppleEvents( Tcl_Interp *interp) /* not used */ { | | > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | *---------------------------------------------------------------------- */ void TkMacOSXInitAppleEvents( Tcl_Interp *interp) /* not used */ { NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager]; static Boolean initialized = FALSE; if (!initialized) { initialized = TRUE; [aeManager setEventHandler:NSApp andSelector:@selector(handleQuitApplicationEvent:withReplyEvent:) |
︙ | ︙ | |||
484 485 486 487 488 489 490 491 | static int ReallyKillMe( Tcl_Event *eventPtr, int flags) { Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp; int quit = Tcl_FindCommand(interp, "::tk::mac::Quit", NULL, 0)!=NULL; | > > > | > > | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | static int ReallyKillMe( Tcl_Event *eventPtr, int flags) { Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp; Tcl_Preserve(interp); int quit = Tcl_FindCommand(interp, "::tk::mac::Quit", NULL, 0)!=NULL; int code = Tcl_EvalEx(interp, quit ? "::tk::mac::Quit" : "exit", -1, TCL_EVAL_GLOBAL); if (code != TCL_OK) { /* * Should be never reached... */ Tcl_BackgroundException(interp, code); } Tcl_Release(interp); return 1; } /* *---------------------------------------------------------------------- * * MissedAnyParameters -- |
︙ | ︙ | |||
527 528 529 530 531 532 533 | err = AEGetAttributePtr(theEvent, keyMissedKeywordAttr, typeWildCard, &returnedType, NULL, 0, &actualSize); return (err != errAEDescNotFound); } | < | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | err = AEGetAttributePtr(theEvent, keyMissedKeywordAttr, typeWildCard, &returnedType, NULL, 0, &actualSize); return (err != errAEDescNotFound); } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXImage.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | int _XInitImageFuncPtrs( XImage *image) { return 0; } | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | int _XInitImageFuncPtrs( XImage *image) { return 0; } /* *---------------------------------------------------------------------- * * TkMacOSXCreateCGImageWithXImage -- * * Create CGImage from XImage, copying the image data. Called * in Tk_PutImage and (currently) nowhere else. |
︙ | ︙ | |||
77 78 79 80 81 82 83 | while (srcPtr < endPtr) { *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))]; } } else { data = memcpy(ckalloc(len), image->data + image->xoffset, len); } if (data) { | | > | | > < | < | | > < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | while (srcPtr < endPtr) { *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))]; } } else { data = memcpy(ckalloc(len), image->data + image->xoffset, len); } if (data) { provider = CGDataProviderCreateWithData(data, data, len, releaseData); } if (provider) { img = CGImageMaskCreate(image->width, image->height, bitsPerComponent, bitsPerPixel, image->bytes_per_line, provider, decode, 0); } } else if ((image->format == ZPixmap) && (image->bits_per_pixel == 32)) { /* * Color image */ CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); if (image->width == 0 && image->height == 0) { /* * CGCreateImage complains on early macOS releases. */ return NULL; } bitsPerComponent = 8; bitsPerPixel = 32; bitmapInfo = (image->byte_order == MSBFirst ? kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big); bitmapInfo |= kCGImageAlphaLast; data = memcpy(ckalloc(len), image->data + image->xoffset, len); if (data) { provider = CGDataProviderCreateWithData(data, data, len, releaseData); } if (provider) { img = CGImageCreate(image->width, image->height, bitsPerComponent, bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo, provider, decode, 0, kCGRenderingIntentDefault); CFRelease(provider); } if (colorspace) { CFRelease(colorspace); } } else { TkMacOSXDbgMsg("Unsupported image type"); } return img; } /* *---------------------------------------------------------------------- * * XGetImage -- * * This function copies data from a pixmap or window into an XImage. It * is essentially never used. At one time it was called by |
︙ | ︙ | |||
175 176 177 178 179 180 181 | unsigned int bytes_per_row, size, row, n, m; unsigned int scalefactor=1, scaled_height=height, scaled_width=width; NSWindow *win = TkMacOSXDrawableWindow(drawable); static enum {unknown, no, yes} has_retina = unknown; if (win && has_retina == unknown) { #ifdef __clang__ | | | < | | | | | | | | | | | | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | unsigned int bytes_per_row, size, row, n, m; unsigned int scalefactor=1, scaled_height=height, scaled_width=width; NSWindow *win = TkMacOSXDrawableWindow(drawable); static enum {unknown, no, yes} has_retina = unknown; if (win && has_retina == unknown) { #ifdef __clang__ has_retina = [win respondsToSelector:@selector(backingScaleFactor)] ? yes : no; #else has_retina = no; #endif } if (has_retina == yes) { /* * We only allow scale factors 1 or 2, as Apple currently does. */ #ifdef __clang__ scalefactor = [win backingScaleFactor] == 2.0 ? 2 : 1; #endif scaled_height *= scalefactor; scaled_width *= scalefactor; } if (format == ZPixmap) { if (width == 0 || height == 0) { return NULL; } bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable, x, y, width, height); if (!bitmap_rep) { TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep"); return NULL; } bitmap_fmt = [bitmap_rep bitmapFormat]; size = [bitmap_rep bytesPerPlane]; bytes_per_row = [bitmap_rep bytesPerRow]; bitmap = ckalloc(size); if (!bitmap || (bitmap_fmt != 0 && bitmap_fmt != 1) || [bitmap_rep samplesPerPixel] != 4 || [bitmap_rep isPlanar] != 0 || bytes_per_row < 4 * scaled_width || size != bytes_per_row * scaled_height) { TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format"); CFRelease(bitmap_rep); return NULL; } memcpy(bitmap, (char *)[bitmap_rep bitmapData], size); CFRelease(bitmap_rep); /* * When Apple extracts a bitmap from an NSView, it may be in either * BGRA or ABGR format. For an XImage we need RGBA. */ struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr; for (row = 0, n = 0; row < scaled_height; row++, n += bytes_per_row) { for (m = n; m < n + 4*scaled_width; m += 4) { R = *(bitmap + m + pixel.r); G = *(bitmap + m + pixel.g); B = *(bitmap + m + pixel.b); A = *(bitmap + m + pixel.a); *(bitmap + m) = R; *(bitmap + m + 1) = G; *(bitmap + m + 2) = B; *(bitmap + m + 3) = A; } } imagePtr = XCreateImage(display, NULL, depth, format, offset, (char*) bitmap, scaled_width, scaled_height, bitmap_pad, bytes_per_row); if (scalefactor == 2) { imagePtr->pixelpower = 1; } } else { /* * There are some calls to XGetImage in the generic Tk code which pass * an XYPixmap rather than a ZPixmap. XYPixmaps should be handled * here. */ TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment."); } return imagePtr; } /* |
︙ | ︙ | |||
319 320 321 322 323 324 325 | if (image && image->data) { unsigned char *srcPtr = ((unsigned char*) image->data) + (y * image->bytes_per_line) + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); switch (image->bits_per_pixel) { | | | | | | | | | | | < | | | | | | | | | | | | | | | > | | | | | | | | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | if (image && image->data) { unsigned char *srcPtr = ((unsigned char*) image->data) + (y * image->bytes_per_line) + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); switch (image->bits_per_pixel) { case 32: r = (*((unsigned int*) srcPtr) >> 16) & 0xff; g = (*((unsigned int*) srcPtr) >> 8) & 0xff; b = (*((unsigned int*) srcPtr) ) & 0xff; /*if (image->byte_order == LSBFirst) { r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0]; } else { r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3]; }*/ break; case 16: r = (*((unsigned short*) srcPtr) >> 7) & 0xf8; g = (*((unsigned short*) srcPtr) >> 2) & 0xf8; b = (*((unsigned short*) srcPtr) << 3) & 0xf8; break; case 8: r = (*srcPtr << 2) & 0xc0; g = (*srcPtr << 4) & 0xc0; b = (*srcPtr << 6) & 0xc0; r |= r >> 2 | r >> 4 | r >> 6; g |= g >> 2 | g >> 4 | g >> 6; b |= b >> 2 | b >> 4 | b >> 6; break; case 4: { unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4); r = (c & 0x04) ? 0xff : 0; g = (c & 0x02) ? 0xff : 0; b = (c & 0x01) ? 0xff : 0; break; } case 1: r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0; break; } } return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
385 386 387 388 389 390 391 392 393 394 395 396 397 398 | int y, unsigned long pixel) { if (image && image->data) { unsigned char *dstPtr = ((unsigned char*) image->data) + (y * image->bytes_per_line) + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); if (image->bits_per_pixel == 32) { *((unsigned int*) dstPtr) = pixel; } else { unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff; unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff; unsigned char b = ((pixel & image->blue_mask) ) & 0xff; switch (image->bits_per_pixel) { | > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | int y, unsigned long pixel) { if (image && image->data) { unsigned char *dstPtr = ((unsigned char*) image->data) + (y * image->bytes_per_line) + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); if (image->bits_per_pixel == 32) { *((unsigned int*) dstPtr) = pixel; } else { unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff; unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff; unsigned char b = ((pixel & image->blue_mask) ) & 0xff; switch (image->bits_per_pixel) { |
︙ | ︙ | |||
416 417 418 419 420 421 422 | (*dstPtr & ~(0x80 >> (x % 8))); break; } } } return 0; } | | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | (*dstPtr & ~(0x80 >> (x % 8))); break; } } } return 0; } /* *---------------------------------------------------------------------- * * XCreateImage -- * * Allocates storage for a new XImage. * |
︙ | ︙ | |||
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | char* data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line) { XImage *ximage; display->request++; ximage = ckalloc(sizeof(XImage)); ximage->height = height; ximage->width = width; ximage->depth = depth; ximage->xoffset = offset; ximage->format = format; ximage->data = data; ximage->obdata = NULL; | > > > | > > | > > | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | char* data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line) { XImage *ximage; display->request++; ximage = ckalloc(sizeof(XImage)); ximage->height = height; ximage->width = width; ximage->depth = depth; ximage->xoffset = offset; ximage->format = format; ximage->data = data; ximage->obdata = NULL; /* * The default pixelpower is 0. This must be explicitly set to 1 in the * case of an XImage extracted from a Retina display. */ ximage->pixelpower = 0; if (format == ZPixmap) { ximage->bits_per_pixel = 32; ximage->bitmap_unit = 32; } else { ximage->bits_per_pixel = 1; ximage->bitmap_unit = 8; } if (bitmap_pad) { ximage->bitmap_pad = bitmap_pad; } else { /* * Use 16 byte alignment for best Quartz perfomance. */ ximage->bitmap_pad = 128; } if (bytes_per_line) { ximage->bytes_per_line = bytes_per_line; } else { ximage->bytes_per_line = ((width * ximage->bits_per_pixel + (ximage->bitmap_pad - 1)) >> 3) & |
︙ | ︙ | |||
507 508 509 510 511 512 513 | } /* *---------------------------------------------------------------------- * * TkPutImage -- * | | | | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | } /* *---------------------------------------------------------------------- * * TkPutImage -- * * Copies a rectangular subimage of an XImage into a drawable. Currently * this is only called by TkImgPhotoDisplay, using a Window as the * drawable. * * Results: * None. * * Side effects: * Draws the image on the specified drawable. * |
︙ | ︙ | |||
555 556 557 558 559 560 561 | */ if (!(macDraw->flags & TK_IS_PIXMAP)) { CGContextSetBlendMode(dc.context, kCGBlendModeSourceAtop); } if (img) { | > | > | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | */ if (!(macDraw->flags & TK_IS_PIXMAP)) { CGContextSetBlendMode(dc.context, kCGBlendModeSourceAtop); } if (img) { /* * If the XImage has big pixels, the source is rescaled to reflect * the actual pixel dimensions. This is not currently used, but * could arise if the image were copied from a retina monitor and * redrawn on an ordinary monitor. */ int pp = image->pixelpower; bounds = CGRectMake(0, 0, image->width, image->height); srcRect = CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp); dstRect = CGRectMake(dest_x, dest_y, width, height); TkMacOSXDrawCGImage(drawable, gc, dc.context, img, gc->foreground, gc->background, bounds, srcRect, dstRect); CFRelease(img); |
︙ | ︙ |
Changes to macosx/tkMacOSXInit.c.
︙ | ︙ | |||
41 42 43 44 45 46 47 | * called while the pool is locked. */ #undef DEBUG_LOCK @implementation TKApplication(TKInit) - (void) _resetAutoreleasePool { | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | * called while the pool is locked. */ #undef DEBUG_LOCK @implementation TKApplication(TKInit) - (void) _resetAutoreleasePool { if ([self poolLock] == 0) { [_mainPool drain]; _mainPool = [NSAutoreleasePool new]; } else { #ifdef DEBUG_LOCK fprintf(stderr, "Pool is locked with count %d!!!!\n", [self poolLock]); #endif } |
︙ | ︙ | |||
97 98 99 100 101 102 103 | [self _setupApplicationNotifications]; /* * Construct the menu bar. */ _defaultMainMenu = nil; [self _setupMenus]; | < | | < | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | [self _setupApplicationNotifications]; /* * Construct the menu bar. */ _defaultMainMenu = nil; [self _setupMenus]; /* * Initialize event processing. */ TkMacOSXInitAppleEvents(_eventInterp); /* * Initialize the graphics context. */ TkMacOSXUseAntialiasedText(_eventInterp, -1); TkMacOSXInitCGDrawing(_eventInterp, TRUE, 0); } -(void)applicationDidFinishLaunching:(NSNotification *)notification { /* * It is not safe to force activation of the NSApp until this method is * called. Activating too early can cause the menu bar to be unresponsive. */ [NSApp activateIgnoringOtherApps: YES]; /* * Process events to ensure that the root window is fully initialized. See * ticket 56a1823c73. */ [NSApp _lockAutoreleasePool]; while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT)) {} [NSApp _unlockAutoreleasePool]; } - (void) _setup: (Tcl_Interp *) interp { |
︙ | ︙ | |||
147 148 149 150 151 152 153 | _mainPool = [NSAutoreleasePool new]; [NSApp setPoolLock:0]; /* * Record the OS version we are running on. */ int minorVersion; | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | _mainPool = [NSAutoreleasePool new]; [NSApp setPoolLock:0]; /* * Record the OS version we are running on. */ int minorVersion; #if MAC_OS_X_VERSION_MAX_ALLOWED < 101000 Gestalt(gestaltSystemVersionMinor, (SInt32*)&minorVersion); #else NSOperatingSystemVersion systemVersion; systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; minorVersion = systemVersion.minorVersion; #endif [NSApp setMacMinorVersion: minorVersion]; |
︙ | ︙ | |||
306 307 308 309 310 311 312 | if (getenv("XCNOSTDIN") != NULL) { close(0); close(1); } /* | | | > > > > > > > > > > > | | < < < < < < < < < < | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | if (getenv("XCNOSTDIN") != NULL) { close(0); close(1); } /* * Instantiate our NSApplication object. This needs to be done before * we check whether to open a console window. */ NSAutoreleasePool *pool = [NSAutoreleasePool new]; [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], @"_NSCanWrapButtonTitles", [NSNumber numberWithInt:-1], @"NSStringDrawingTypesetterBehavior", nil]]; [TKApplication sharedApplication]; [pool drain]; [NSApp _setup:interp]; [NSApp finishLaunching]; Tk_MacOSXSetupTkNotifier(); /* * If the root window is mapped before the App has finished launching * it will open off screen (see ticket 56a1823c73). To avoid this we * ask Tk to process an event with no wait. We expect Tcl_DoOneEvent * to wait until the Mac event loop has been created and then return * immediately since the queue is empty. */ Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT); /* * If we don't have a TTY and stdin is a special character file of * length 0, (e.g. /dev/null, which is what Finder sets when double * clicking Wish) then use the Tk based console interpreter. */ if (getenv("TK_CONSOLE") || (!isatty(0) && (fstat(0, &st) || (S_ISCHR(st.st_mode) && st.st_blocks == 0)))) { Tk_InitConsoleChannels(interp); Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDIN)); Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDOUT)); Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR)); /* * Only show the console if we don't have a startup script and * tcl_interactive hasn't been set already. */ if (Tcl_GetStartupScript(NULL) == NULL) { const char *intvar = Tcl_GetVar2(interp, "tcl_interactive", NULL, TCL_GLOBAL_ONLY); if (intvar == NULL) { Tcl_SetVar2(interp, "tcl_interactive", NULL, "1", TCL_GLOBAL_ONLY); } } if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) { return TCL_ERROR; } } } if (tkLibPath[0] != '\0') { Tcl_SetVar2(interp, "tk_library", NULL, tkLibPath, TCL_GLOBAL_ONLY); } if (scriptPath[0] != '\0') { Tcl_SetVar2(interp, "auto_path", NULL, scriptPath, TCL_GLOBAL_ONLY|TCL_LIST_ELEMENT|TCL_APPEND_VALUE); } Tcl_CreateObjCommand(interp, "::tk::mac::standardAboutPanel", TkMacOSXStandardAboutPanelObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::mac::iconBitmap", TkMacOSXIconBitmapObjCmd, NULL, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TkpGetAppName -- |
︙ | ︙ |
Changes to macosx/tkMacOSXKeyEvent.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | #endif */ #define NS_KEYLOG 0 static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ static NSWindow *keyboardGrabNSWindow = nil; | | > < < | > | | | | | | | | < | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #endif */ #define NS_KEYLOG 0 static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ static NSWindow *keyboardGrabNSWindow = nil; /* NSWindow for the current keyboard grab * window. */ static NSModalSession modalSession = nil; static BOOL processingCompose = NO; static BOOL finishedCompose = NO; static int caret_x = 0, caret_y = 0, caret_height = 0; static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state); static unsigned isFunctionKey(unsigned int code); unsigned short releaseCode; #pragma mark TKApplication(TKKeyEvent) @implementation TKApplication(TKKeyEvent) - (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); #endif NSWindow *w; NSEventType type = [theEvent type]; NSUInteger modifiers = ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); NSUInteger len = 0; BOOL repeat = NO; unsigned short keyCode = [theEvent keyCode]; NSString *characters = nil, *charactersIgnoringModifiers = nil; static NSUInteger savedModifiers = 0; static NSMutableArray *nsEvArray; if (nsEvArray == nil) { nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1]; processingCompose = NO; } w = [theEvent window]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; XEvent xEvent; if (!winPtr) { |
︙ | ︙ | |||
105 106 107 108 109 110 111 | #endif break; default: return theEvent; /* Unrecognized key event. */ } | > | > > | | | | | | | | | | < > | | | | | | | | > | | | < < > | | | | | | | | | | | | | | | | | | | | > | | > > | | | | | | | | | | | | | | | | | | | | | | | < | | | | > | < | | > > > > > > > | | | | | > | | > | > > | | | > > | > > | | | < | | | | | | | | | | | | | | | > | | > | | | > | | | | | | > > | | > | | | > | | | | | | | | | | | | | | | | > | | < > | | > > | > | | | | | | | | > | > > | | | | > | | | > | | > | > | | > | > > | | > | | | > | | | | < < | > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | #endif break; default: return theEvent; /* Unrecognized key event. */ } /* * Create an Xevent to add to the Tk queue. */ if (!processingCompose) { unsigned int state = 0; if (modifiers & NSAlphaShiftKeyMask) { state |= LockMask; } if (modifiers & NSShiftKeyMask) { state |= ShiftMask; } if (modifiers & NSControlKeyMask) { state |= ControlMask; } if (modifiers & NSCommandKeyMask) { state |= Mod1Mask; /* command key */ } if (modifiers & NSAlternateKeyMask) { state |= Mod2Mask; /* option key */ } if (modifiers & NSNumericPadKeyMask) { state |= Mod3Mask; } if (modifiers & NSFunctionKeyMask) { state |= Mod4Mask; } /* * Events are only received for the front Window on the Macintosh. So * to build an XEvent we look up the Tk window associated to the Front * window. If a different window has a local grab we ignore the event. */ TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; if (tkwin) { TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; if (grabWinPtr && grabWinPtr != winPtr && !winPtr->dispPtr->grabFlags /* this means the grab is local. */ && grabWinPtr->mainPtr == winPtr->mainPtr) { return theEvent; } } else { tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; } if (!tkwin) { TkMacOSXDbgMsg("tkwin == NULL"); return theEvent; /* Give up. No window for this event. */ } /* * If it's a function key, or we have modifiers other than Shift or * Alt, pass it straight to Tk. Otherwise we'll send for input * processing. */ int code = (len == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0]; if (type != NSKeyDown || isFunctionKey(code) || (len > 0 && state & (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask))) { XEvent xEvent; setupXEvent(&xEvent, w, state); if (type == NSFlagsChanged) { if (savedModifiers > modifiers) { xEvent.xany.type = KeyRelease; } else { xEvent.xany.type = KeyPress; } /* * Use special '-1' to signify a special keycode to our * platform specific code in tkMacOSXKeyboard.c. This is rather * like what happens on Windows. */ xEvent.xany.send_event = -1; /* * Set keycode (which was zero) to the changed modifier */ xEvent.xkey.keycode = (modifiers ^ savedModifiers); } else { if (type == NSKeyUp || repeat) { xEvent.xany.type = KeyRelease; } else { xEvent.xany.type = KeyPress; } /* * For command key, take input manager's word so things like * dvorak / qwerty layout work. */ if ((modifiers & NSCommandKeyMask) == NSCommandKeyMask && (modifiers & NSAlternateKeyMask) != NSAlternateKeyMask && len > 0 && !isFunctionKey(code)) { // head off keycode-based translation in tkMacOSXKeyboard.c xEvent.xkey.nbytes = [characters length]; //len } if ([characters length] > 0) { xEvent.xkey.keycode = (keyCode << 16) | (UInt16) [characters characterAtIndex:0]; if (![characters getCString:xEvent.xkey.trans_chars maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) { /* prevent SF bug 2907388 (crash on some composite chars) */ //PENDING: we might not need this anymore TkMacOSXDbgMsg("characters too long"); return theEvent; } } if (repeat) { Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); xEvent.xany.type = KeyPress; xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); } } Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); savedModifiers = modifiers; return theEvent; } /* if send straight to TK */ } /* if not processing compose */ if (type == NSKeyDown) { if (NS_KEYLOG) { TKLog(@"keyDown: %s compose sequence.\n", processingCompose == YES ? "Continue" : "Begin"); } processingCompose = YES; [nsEvArray addObject: theEvent]; [[w contentView] interpretKeyEvents: nsEvArray]; [nsEvArray removeObject: theEvent]; } savedModifiers = modifiers; return theEvent; } @end @implementation TKContentView -(id)init { if (self = [super init]) { _needsRedisplay = NO; } return self; } /* <NSTextInput> implementation (called through interpretKeyEvents:]). */ /* <NSTextInput>: called when done composing; NOTE: also called when we delete over working text, followed immed. by doCommandBySelector: deleteBackward: */ - (void)insertText: (id)aString { int i, len = [(NSString *) aString length]; XEvent xEvent; if (NS_KEYLOG) { TKLog(@"insertText '%@'\tlen = %d", aString, len); } processingCompose = NO; finishedCompose = YES; /* * First, clear any working text. */ if (privateWorkingText != nil) { [self deleteWorkingText]; } /* * Now insert the string as keystrokes. */ setupXEvent(&xEvent, [self window], 0); xEvent.xany.type = KeyPress; for (i =0; i<len; i++) { xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i]; [[aString substringWithRange: NSMakeRange(i,1)] getCString: xEvent.xkey.trans_chars maxLength: XMaxTransChars encoding: NSUTF8StringEncoding]; xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars); xEvent.xany.type = KeyPress; releaseCode = (UInt16) [aString characterAtIndex: 0]; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } releaseCode = (UInt16) [aString characterAtIndex: 0]; } /* <NSTextInput>: inserts display of composing characters */ - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange { NSString *str = [aString respondsToSelector: @selector (string)] ? [aString string] : aString; if (NS_KEYLOG) { TKLog(@"setMarkedText '%@' len =%lu range %lu from %lu", str, (unsigned long) [str length], (unsigned long) selRange.length, (unsigned long) selRange.location); } if (privateWorkingText != nil) { [self deleteWorkingText]; } if ([str length] == 0) { return; } processingCompose = YES; privateWorkingText = [str copy]; //PENDING: insert workingText underlined } - (BOOL)hasMarkedText { return privateWorkingText != nil; } - (NSRange)markedRange { NSRange rng = privateWorkingText != nil ? NSMakeRange(0, [privateWorkingText length]) : NSMakeRange(NSNotFound, 0); if (NS_KEYLOG) { TKLog(@"markedRange request"); } return rng; } - (void)unmarkText { if (NS_KEYLOG) { TKLog(@"unmark (accept) text"); } [self deleteWorkingText]; processingCompose = NO; } /* used to position char selection windows, etc. */ - (NSRect)firstRectForCharacterRange: (NSRange)theRange { NSRect rect; NSPoint pt; pt.x = caret_x; pt.y = caret_y; pt = [self convertPoint: pt toView: nil]; pt = [[self window] tkConvertPointToScreen: pt]; pt.y -= caret_height; rect.origin = pt; rect.size.width = caret_height; rect.size.height = caret_height; return rect; } - (NSInteger)conversationIdentifier { return (NSInteger) self; } - (void)doCommandBySelector: (SEL)aSelector { if (NS_KEYLOG) { TKLog(@"doCommandBySelector: %@", NSStringFromSelector(aSelector)); } processingCompose = NO; if (aSelector == @selector (deleteBackward:)) { /* * Happens when user backspaces over an ongoing composition: * throw a 'delete' into the event queue. */ XEvent xEvent; setupXEvent(&xEvent, [self window], 0); xEvent.xany.type = KeyPress; xEvent.xkey.nbytes = 1; xEvent.xkey.keycode = (0x33 << 16) | 0x7F; xEvent.xkey.trans_chars[0] = 0x7F; xEvent.xkey.trans_chars[1] = 0x0; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } } - (NSArray *)validAttributesForMarkedText { static NSArray *arr = nil; if (arr == nil) { arr = [NSArray new]; } /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */ return arr; } - (NSRange)selectedRange { if (NS_KEYLOG) { TKLog(@"selectedRange request"); } return NSMakeRange(NSNotFound, 0); } - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint { if (NS_KEYLOG) { TKLog(@"characterIndexForPoint request"); } return 0; } - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange { static NSAttributedString *str = nil; if (str == nil) { str = [NSAttributedString new]; } if (NS_KEYLOG) { TKLog(@"attributedSubstringFromRange request"); } return str; } /* End <NSTextInput> impl. */ @synthesize needsRedisplay = _needsRedisplay; @end @implementation TKContentView(TKKeyEvent) /* delete display of composing characters [not in <NSTextInput>] */ - (void)deleteWorkingText { if (privateWorkingText == nil) { return; } if (NS_KEYLOG) { TKLog(@"deleteWorkingText len = %lu\n", (unsigned long)[privateWorkingText length]); } [privateWorkingText release]; privateWorkingText = nil; processingCompose = NO; //PENDING: delete working text } @end /* * Set up basic fields in xevent for keyboard input. */ static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state) { TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; if (!winPtr) { return; } memset(xEvent, 0, sizeof(XEvent)); xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); xEvent->xany.send_event = false; |
︙ | ︙ | |||
493 494 495 496 497 498 499 | Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time) { keyboardGrabWinPtr = Tk_IdToWindow(display, grab_window); | | > | | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time) { keyboardGrabWinPtr = Tk_IdToWindow(display, grab_window); TkWindow *captureWinPtr = (TkWindow *) TkMacOSXGetCapture(); if (keyboardGrabWinPtr && captureWinPtr) { NSWindow *w = TkMacOSXDrawableWindow(grab_window); MacDrawable *macWin = (MacDrawable *) grab_window; if (w && macWin->toplevel->winPtr == (TkWindow *) captureWinPtr) { if (modalSession) { Tcl_Panic("XGrabKeyboard: already grabbed"); } keyboardGrabNSWindow = w; [w retain]; modalSession = [NSApp beginModalSessionForWindow:w]; } |
︙ | ︙ | |||
617 618 619 620 621 622 623 | y += Tk_Y(tkwin); tkwin = Tk_Parent(tkwin); if (tkwin == NULL) { return; } } | > | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | > | | | > > | | | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | y += Tk_Y(tkwin); tkwin = Tk_Parent(tkwin); if (tkwin == NULL) { return; } } /* * But adjust for fact that NS uses flipped view. */ y = Tk_Height(tkwin) - y; caret_x = x; caret_y = y; caret_height = height; } static unsigned convert_ns_to_X_keysym[] = { NSHomeFunctionKey, 0x50, NSLeftArrowFunctionKey, 0x51, NSUpArrowFunctionKey, 0x52, NSRightArrowFunctionKey, 0x53, NSDownArrowFunctionKey, 0x54, NSPageUpFunctionKey, 0x55, NSPageDownFunctionKey, 0x56, NSEndFunctionKey, 0x57, NSBeginFunctionKey, 0x58, NSSelectFunctionKey, 0x60, NSPrintFunctionKey, 0x61, NSExecuteFunctionKey, 0x62, NSInsertFunctionKey, 0x63, NSUndoFunctionKey, 0x65, NSRedoFunctionKey, 0x66, NSMenuFunctionKey, 0x67, NSFindFunctionKey, 0x68, NSHelpFunctionKey, 0x6A, NSBreakFunctionKey, 0x6B, NSF1FunctionKey, 0xBE, NSF2FunctionKey, 0xBF, NSF3FunctionKey, 0xC0, NSF4FunctionKey, 0xC1, NSF5FunctionKey, 0xC2, NSF6FunctionKey, 0xC3, NSF7FunctionKey, 0xC4, NSF8FunctionKey, 0xC5, NSF9FunctionKey, 0xC6, NSF10FunctionKey, 0xC7, NSF11FunctionKey, 0xC8, NSF12FunctionKey, 0xC9, NSF13FunctionKey, 0xCA, NSF14FunctionKey, 0xCB, NSF15FunctionKey, 0xCC, NSF16FunctionKey, 0xCD, NSF17FunctionKey, 0xCE, NSF18FunctionKey, 0xCF, NSF19FunctionKey, 0xD0, NSF20FunctionKey, 0xD1, NSF21FunctionKey, 0xD2, NSF22FunctionKey, 0xD3, NSF23FunctionKey, 0xD4, NSF24FunctionKey, 0xD5, NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */ NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */ NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */ NSTabCharacter, 0x09, 0x19, 0x09, /* left tab->regular since pass shift */ NSCarriageReturnCharacter, 0x0D, NSNewlineCharacter, 0x0D, NSEnterCharacter, 0x8D, 0x1B, 0x1B /* escape */ }; static unsigned isFunctionKey( unsigned code) { const unsigned last_keysym = (sizeof(convert_ns_to_X_keysym) / sizeof(convert_ns_to_X_keysym[0])); unsigned keysym; for (keysym = 0; keysym < last_keysym; keysym += 2) { if (code == convert_ns_to_X_keysym[keysym]) { return 0xFF00 | convert_ns_to_X_keysym[keysym + 1]; } } return 0; } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXMenu.c.
︙ | ︙ | |||
189 190 191 192 193 194 195 | [super insertItem:newItem atIndex:index + _tkOffset]; _tkItemCount++; } - (void) insertItem: (NSMenuItem *) newItem atIndex: (NSInteger) index { if (_tkMenu && index >= 0) { | | | | | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | [super insertItem:newItem atIndex:index + _tkOffset]; _tkItemCount++; } - (void) insertItem: (NSMenuItem *) newItem atIndex: (NSInteger) index { if (_tkMenu && index >= 0) { if ((NSUInteger) index <= _tkOffset) { _tkOffset++; } else { NSAssert((NSUInteger) index >= _tkItemCount + _tkOffset, @"Cannot insert in the middle of Tk menu"); } } [super insertItem:newItem atIndex:index]; } - (void) removeItemAtIndex: (NSInteger) index { if (_tkMenu && index >= 0) { if ((NSUInteger) index < _tkOffset) { _tkOffset--; } else if ((NSUInteger) index < _tkItemCount + _tkOffset) { _tkItemCount--; } } [super removeItemAtIndex:index]; } - (NSMenuItem *) newTkMenuItem: (TkMenuEntry *) mePtr { NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:@selector(tkMenuItemInvoke:) keyEquivalent:@""]; [menuItem setTarget:self]; [menuItem setTag:(NSInteger) mePtr]; return menuItem; } @end @implementation TKMenu(TKMenuActions) - (BOOL) validateMenuItem: (NSMenuItem *) menuItem |
︙ | ︙ | |||
248 249 250 251 252 253 254 | * With the delegate matching key equivalents, when a menu action is sent * in response to a key equivalent, the sender is the whole menu and not the * specific menu item. We use this to ignore key equivalents for Tk * menus (as Tk handles them directly via bindings). */ if ([sender isKindOfClass:[NSMenuItem class]]) { | | | | > | | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | * With the delegate matching key equivalents, when a menu action is sent * in response to a key equivalent, the sender is the whole menu and not the * specific menu item. We use this to ignore key equivalents for Tk * menus (as Tk handles them directly via bindings). */ if ([sender isKindOfClass:[NSMenuItem class]]) { NSMenuItem *menuItem = (NSMenuItem *) sender; TkMenu *menuPtr = (TkMenu *) _tkMenu; TkMenuEntry *mePtr = (TkMenuEntry *) [menuItem tag]; if (menuPtr && mePtr) { Tcl_Interp *interp = menuPtr->interp; /* * Add time for errors to fire if necessary. This is sub-optimal * but avoids issues with Tcl/Cocoa event loop integration. */ //Tcl_Sleep(100); Tcl_Preserve(interp); Tcl_Preserve(menuPtr); int result = TkInvokeMenu(interp, menuPtr, mePtr->index); |
︙ | ︙ | |||
301 302 303 304 305 306 307 | * Command-Shift-? has not been allowed as a keyboard equivalent since * the first aqua port, for some mysterious reason. */ return NO; } else if (modifiers == (NSControlKeyMask | NSShiftKeyMask) && [event keyCode] == 48) { | | | < | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | * Command-Shift-? has not been allowed as a keyboard equivalent since * the first aqua port, for some mysterious reason. */ return NO; } else if (modifiers == (NSControlKeyMask | NSShiftKeyMask) && [event keyCode] == 48) { /* * Starting with OSX 10.12 Control-Tab and Control-Shift-Tab are used * to select window tabs. But for some even more mysterious reason the * Control-Shift-Tab event has character 0x19 = NSBackTabCharacter * rather than 0x09 = NSTabCharacter. At the same time, the * keyEquivalent must be \0x09 in order for it to be displayed * correctly in the menu. This makes it impossible for the standard * "Select Previous Tab" to work correctly, unless we intervene. */ key = @"\t"; } else if (([event modifierFlags] & NSCommandKeyMask) == NSCommandKeyMask) { /* * If the command modifier is set, use the full character string so * things like the dvorak / qwerty layout will work. */ key = [event characters]; } |
︙ | ︙ | |||
646 647 648 649 650 651 652 | attributes = TkMacOSXNSFontAttributesForFont(Tk_GetFontFromObj( mePtr->menuPtr->tkwin, fontPtr)); if (gc->foreground != defaultFg || gc->background != defaultBg) { NSColor *color = TkMacOSXGetNSColor(gc, gc->foreground!=defaultFg? gc->foreground:gc->background); attributes = [[attributes mutableCopy] autorelease]; | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | attributes = TkMacOSXNSFontAttributesForFont(Tk_GetFontFromObj( mePtr->menuPtr->tkwin, fontPtr)); if (gc->foreground != defaultFg || gc->background != defaultBg) { NSColor *color = TkMacOSXGetNSColor(gc, gc->foreground!=defaultFg? gc->foreground:gc->background); attributes = [[attributes mutableCopy] autorelease]; [(NSMutableDictionary *) attributes setObject:color forKey:NSForegroundColorAttributeName]; } if (attributes) { attributedTitle = [[[NSAttributedString alloc] initWithString:title attributes:attributes] autorelease]; } } |
︙ | ︙ | |||
686 687 688 689 690 691 692 | */ submenu = nil; } else { [submenu setTitle:title]; if ([menuItem isEnabled]) { | > > | | | > > | | > | | > > | | > > | > > | | | < | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 | */ submenu = nil; } else { [submenu setTitle:title]; if ([menuItem isEnabled]) { /* * This menuItem might have been previously disabled (XXX: * track this), which would have disabled entries; we must * re-enable the entries here. */ int i = 0; NSArray *itemArray = [submenu itemArray]; for (NSMenuItem *item in itemArray) { TkMenuEntry *submePtr = menuRefPtr->menuPtr->entries[i]; /* * Work around an apparent bug where itemArray can have * more items than the menu's entries[] array. */ if (i >= (int) menuRefPtr->menuPtr->numEntries) { break; } [item setEnabled: !(submePtr->state == ENTRY_DISABLED)]; i++; } } } } } [menuItem setSubmenu:submenu]; return TCL_OK; } |
︙ | ︙ | |||
751 752 753 754 755 756 757 | } /* *---------------------------------------------------------------------- * * TkpPostMenu -- * | | | | | | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | } /* *---------------------------------------------------------------------- * * TkpPostMenu -- * * Posts a menu on the screen. If entry is < 0 then the menu is drawn so * its top left corner is located at the point with screen coordinates * (x,y). Otherwise the top left corner of the specified entry is located * at that point. * * Results: * Returns a standard Tcl result. * * Side effects: * The menu is posted and handled. * |
︙ | ︙ | |||
824 825 826 827 828 829 830 | } /* *---------------------------------------------------------------------- * * TkpPostTearoffMenu -- * | | | | | | | | | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | } /* *---------------------------------------------------------------------- * * TkpPostTearoffMenu -- * * Tearoff menus are not supported on the Mac. This placeholder function, * which is simply a copy of the unix function, posts a completely useless * window with a black background on the screen. If entry is < 0 then the * window is positioned so that its top left corner is located at the * point with screen coordinates (x, y). Otherwise the window position is * offset so that top left corner of the specified entry would be located * at that point, if there actually were a menu. * * Mac menus steal all mouse or keyboard input from the application until * the menu is dismissed, with or without a selection, by a mouse or key * event. Posting a Mac menu in a regression test will cause the test to * halt waiting for user input. This is why the TkpPostMenu function is * not being used as the placeholder. * |
︙ | ︙ | |||
858 859 860 861 862 863 864 | int x, int y, int index) /* The screen coordinates where the top left * corner of the menu, or of the specified * entry, will be located. */ { int vRootX, vRootY, vRootWidth, vRootHeight; int result; | | | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | int x, int y, int index) /* The screen coordinates where the top left * corner of the menu, or of the specified * entry, will be located. */ { int vRootX, vRootY, vRootWidth, vRootHeight; int result; if (index >= (int) menuPtr->numEntries) { index = menuPtr->numEntries - 1; } if (index >= 0) { y -= menuPtr->entries[index]->y; } TkActivateMenuEntry(menuPtr, -1); |
︙ | ︙ | |||
956 957 958 959 960 961 962 | } /* *---------------------------------------------------------------------- * * TkpSetMainMenubar -- * | | | | | | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 | } /* *---------------------------------------------------------------------- * * TkpSetMainMenubar -- * * Puts the menu associated with a window into the menubar. Should only be * called when the window is in front. * * This is a no-op on all other platforms. On OS X it is a no-op when * passed a NULL menuName or a nonexistent menuName, with an exception for * the first call in a new interpreter. In that special case, passing a * NULL menuName installs the default menu. * * Results: * None. * * Side effects: * The menubar may be changed. |
︙ | ︙ | |||
989 990 991 992 993 994 995 | /* * We will be called when an embedded window receives an ActivationNotify * event, but we should not change the menubar in that case. */ if (Tk_IsEmbedded(winPtr)) { | | | > | | | > > | | < | | | 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | /* * We will be called when an embedded window receives an ActivationNotify * event, but we should not change the menubar in that case. */ if (Tk_IsEmbedded(winPtr)) { return; } if (menuName) { Tk_Window menubar = NULL; if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr && winPtr->wmInfoPtr->menuPtr->masterMenuPtr) { menubar = winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin; } /* * Attempt to find the NSMenu directly. If that fails, ask Tk to find * it. */ if (menubar != NULL && strcmp(menuName, Tk_PathName(menubar)) == 0) { menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData; } else { TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp, menuName); if (menuRefPtr && menuRefPtr->menuPtr && menuRefPtr->menuPtr->platformData) { menu = (TKMenu *) menuRefPtr->menuPtr->platformData; } } } /* * If we couldn't find a menu, do nothing unless the window belongs to a * different application. In that case, install the default menubar. */ if (menu || interp != currentInterp) { [NSApp tkSetMainMenu:menu]; } currentInterp = interp; } /* *---------------------------------------------------------------------- * * CheckForSpecialMenu -- * * Given a menu, check to see whether or not it is a cascade in a menubar * with one of the special names ".apple", ".help" or ".window". If it is, * the entry that points to this menu will be marked. * * Results: * None. * * Side effects: * Will set entryFlags appropriately. * |
︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth; TkMenuEntry *mePtr; int haveAccel = 0; /* * Do nothing if this menu is a clone. */ if (menuPtr->tkwin == NULL || menuPtr->masterMenuPtr != menuPtr) { return; } | > | | | | | | | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 | int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth; TkMenuEntry *mePtr; int haveAccel = 0; /* * Do nothing if this menu is a clone. */ if (menuPtr->tkwin == NULL || menuPtr->masterMenuPtr != menuPtr) { return; } menuSize = [(NSMenu *) menuPtr->platformData size]; Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, &borderWidth); Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, &activeBorderWidth); x = y = borderWidth; windowHeight = maxWidth = 0; maxIndicatorSpace = 0; /* * On the Mac especially, getting font metrics can be quite slow, so we * want to do it intelligently. We are going to precalculate them and pass * them down to all of the measuring and drawing routines. We will measure * the font metrics of the menu once. If an entry does not have its own * font set, then we give the geometry/drawing routines the menu's font and * metrics. If an entry has its own font, we will measure that font and * give all of the geometry/drawing the entry's font and metrics. */ menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); Tk_GetFontMetrics(menuFont, &menuMetrics); menuModifierCharWidth = ModifierCharWidth(menuFont); for (i = 0; i < (int) menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; if (mePtr->type == CASCADE_ENTRY || mePtr->accelLength > 0) { haveAccel = 1; break; } } for (i = 0; i < (int) menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; if (mePtr->type == TEAROFF_ENTRY) { continue; } if (mePtr->fontPtr == NULL) { tkfont = menuFont; fmPtr = &menuMetrics; |
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | * (if any), and the width of the accelerator to be displayed to * the right of the label (if any). These sizes depend, of course, * on the type of the entry. */ NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; int haveImage = 0, width = 0, height = 0; if (mePtr->image) { Tk_SizeOfImage(mePtr->image, &width, &height); haveImage = 1; height += 2; /* tweak */ } else if (mePtr->bitmapPtr) { Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height); haveImage = 1; height += 2; /* tweak */ } if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { NSAttributedString *attrTitle = [menuItem attributedTitle]; NSSize size; | > > | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | * (if any), and the width of the accelerator to be displayed to * the right of the label (if any). These sizes depend, of course, * on the type of the entry. */ NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; int haveImage = 0, width = 0, height = 0; if (mePtr->image) { Tk_SizeOfImage(mePtr->image, &width, &height); haveImage = 1; height += 2; /* tweak */ } else if (mePtr->bitmapPtr) { Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height); haveImage = 1; height += 2; /* tweak */ } if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { NSAttributedString *attrTitle = [menuItem attributedTitle]; NSSize size; |
︙ | ︙ | |||
1409 1410 1411 1412 1413 1414 1415 | NSMenuItem *menuItem) { TkMenu *menuPtr = [menu tkMenu]; if (menuPtr) { int index = [menu tkIndexOfItem:menuItem]; | | | 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 | NSMenuItem *menuItem) { TkMenu *menuPtr = [menu tkMenu]; if (menuPtr) { int index = [menu tkIndexOfItem:menuItem]; if (index < 0 || index >= (int) menuPtr->numEntries || (menuPtr->entries[index])->state == ENTRY_DISABLED) { TkActivateMenuEntry(menuPtr, -1); } else { TkActivateMenuEntry(menuPtr, index); MenuSelectEvent(menuPtr); return true; } |
︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 | void RecursivelyClearActiveMenu( TkMenu *menuPtr) /* The menu to reset. */ { int i; TkActivateMenuEntry(menuPtr, -1); | | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | void RecursivelyClearActiveMenu( TkMenu *menuPtr) /* The menu to reset. */ { int i; TkActivateMenuEntry(menuPtr, -1); for (i = 0; i < (int) menuPtr->numEntries; i++) { TkMenuEntry *mePtr = menuPtr->entries[i]; if (mePtr->type == CASCADE_ENTRY && (mePtr->childMenuRefPtr != NULL) && (mePtr->childMenuRefPtr->menuPtr != NULL)) { RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr); } |
︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 | /* *---------------------------------------------------------------------- * * TkMacOSXUseID -- * * Take the ID out of the available list for new menus. Used by the | | | 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 | /* *---------------------------------------------------------------------- * * TkMacOSXUseID -- * * Take the ID out of the available list for new menus. Used by the * default menu bar's menus so that they do not get created at the Tk * level. See TkMacOSXGetNewMenuID for more information. * * Results: * Returns TCL_OK if the id was not in use. Returns TCL_ERROR if the id * was in use. * * Side effects: |
︙ | ︙ | |||
1802 1803 1804 1805 1806 1807 1808 | } /* *---------------------------------------------------------------------- * * TkMacOSXDispatchMenuEvent -- * | | < | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 | } /* *---------------------------------------------------------------------- * * TkMacOSXDispatchMenuEvent -- * * Given a menu id and an item, dispatches the command associated with it. * * Results: * None. * * Side effects: * Commands for the event are scheduled for execution at idle time. * |
︙ | ︙ | |||
1853 1854 1855 1856 1857 1858 1859 | } /* *---------------------------------------------------------------------- * * TkMacOSXSetHelpMenuItemCount -- * | | | > | | 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 | } /* *---------------------------------------------------------------------- * * TkMacOSXSetHelpMenuItemCount -- * * Has to be called after the first call to InsertMenu. Sets up the global * variable for the number of items in the unmodified help menu. * * NB: Nobody uses this any more, since you can get the number of system * help items from HMGetHelpMenu trivially. But it is in the stubs * table... * * Results: * None. * * Side effects: |
︙ | ︙ |
Changes to macosx/tkMacOSXMenubutton.c.
1 2 3 | /* * tkMacOSXMenubutton.c -- * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 | /* * tkMacOSXMenubutton.c -- * * This file implements the Macintosh specific portion of the menubutton * widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2006-2007 Daniel A. Steffen <[email protected]> * Copyright 2007 Revar Desmera. * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * |
︙ | ︙ | |||
28 29 30 31 32 33 34 | typedef struct { Tk_3DBorder border; int relief; GC gc; int hasImageOrBitmap; } DrawParams; | < | > | | | | | | > | | | | | | | > | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | typedef struct { Tk_3DBorder border; int relief; GC gc; int hasImageOrBitmap; } DrawParams; /* * Declaration of Mac specific button structure. */ typedef struct MacMenuButton { TkMenuButton info; /* Generic button info. */ int flags; ThemeButtonKind btnkind; HIThemeButtonDrawInfo drawinfo; HIThemeButtonDrawInfo lastdrawinfo; DrawParams drawParams; } MacMenuButton; /* * Forward declarations for static functions defined later in this file: */ static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); static void MenuButtonBackgroundDrawCB(MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); static void MenuButtonContentDrawCB(ThemeButtonKind kind, const HIThemeButtonDrawInfo *info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); static void TkMacOSXComputeMenuButtonParams(TkMenuButton *butPtr, ThemeButtonKind *btnkind, HIThemeButtonDrawInfo *drawinfo); static void TkMacOSXComputeMenuButtonDrawParams( TkMenuButton *butPtr, DrawParams *dpPtr); static void TkMacOSXDrawMenuButton(MacMenuButton *butPtr, GC gc, Pixmap pixmap); static void DrawMenuButtonImageAndText(TkMenuButton *butPtr); /* * The structure below defines menubutton class behavior by means of * procedures that can be invoked from generic window code. */ Tk_ClassProcs tkpMenubuttonClass = { |
︙ | ︙ | |||
129 130 131 132 133 134 135 | TkMenuButton * TkpCreateMenuButton( Tk_Window tkwin) { MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); | | < | < | | | | | | > | > > > | > > | | < | | | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | TkMenuButton * TkpCreateMenuButton( Tk_Window tkwin) { MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); Tk_CreateEventHandler(tkwin, ActivateMask, MenuButtonEventProc, mbPtr); mbPtr->flags = FIRST_DRAW; mbPtr->btnkind = kThemePopupButton; bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo)); bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo)); return (TkMenuButton *) mbPtr; } /* *---------------------------------------------------------------------- * * TkpDisplayMenuButton -- * * This procedure is invoked to display a menubutton widget. * * Results: * None. * * Side effects: * Commands are output to X to display the menubutton in its current mode. * *---------------------------------------------------------------------- */ void TkpDisplayMenuButton( ClientData clientData) /* Information about widget. */ { MacMenuButton *mbPtr = clientData; TkMenuButton *butPtr = clientData; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; DrawParams *dpPtr = &mbPtr->drawParams; butPtr->flags &= ~REDRAW_PENDING; if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } pixmap = (Pixmap) Tk_WindowId(tkwin); TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr); /* * Set up clipping region. Make sure the we are using the port for this * button, or we will set the wrong window's clip. */ TkMacOSXSetUpClippingRgn(pixmap); /* * Draw the native portion of the buttons. */ TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap); /* * Draw highlight border, if needed. */ if (butPtr->highlightWidth < 3) { if (butPtr->flags & GOT_FOCUS) { GC gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap); TkMacOSXDrawSolidBorder(tkwin, gc, 0, butPtr->highlightWidth); } } } /* *---------------------------------------------------------------------- * * TkpDestroyMenuButton -- * * Free data structures associated with the menubutton control. This is a * no-op on the Mac. * * Results: * None. * * Side effects: * None. * |
︙ | ︙ | |||
275 276 277 278 279 280 281 | txtWidth = butPtr->textWidth; txtHeight = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); } /* | | | | | | | | | | | | | < | | | | | | | | < | | | | | | | < | > | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | txtWidth = butPtr->textWidth; txtHeight = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); } /* * If the button is compound (ie, it shows both an image and text), the new * geometry is a combination of the image and text geometry. We only honor * the compound bit if the button has both text and an image, because * otherwise it is not really a compound button. */ if (haveImage && haveText) { switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: /* * Image is above or below text */ height += txtHeight + butPtr->padY; width = (width > txtWidth ? width : txtWidth); break; case COMPOUND_LEFT: case COMPOUND_RIGHT: /* * Image is left or right of text */ width += txtWidth + butPtr->padX; height = (height > txtHeight ? height : txtHeight); break; case COMPOUND_CENTER: /* * Image and text are superimposed */ width = (width > txtWidth ? width : txtWidth); height = (height > txtHeight ? height : txtHeight); break; case COMPOUND_NONE: break; } if (butPtr->width > 0) { width = butPtr->width; } if (butPtr->height > 0) { height = butPtr->height; |
︙ | ︙ | |||
341 342 343 344 345 346 347 | width = butPtr->width * avgWidth + 2*butPtr->padX; } if (butPtr->height > 0) { height = butPtr->height * fm.linespace + 2*butPtr->padY; } } } | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | width = butPtr->width * avgWidth + 2*butPtr->padX; } if (butPtr->height > 0) { height = butPtr->height * fm.linespace + 2*butPtr->padY; } } } butPtr->inset = highlightWidth + butPtr->borderWidth; width += LEFT_INSET + RIGHT_INSET + 2*butPtr->inset; height += 2*butPtr->inset; height = height < MIN_HEIGHT ? MIN_HEIGHT : height; Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } |
︙ | ︙ | |||
367 368 369 370 371 372 373 | * Side effects: * The image and text are drawn. * *---------------------------------------------------------------------- */ void DrawMenuButtonImageAndText( | | | | | | < | < | < | < | < | < < | | < | < < < < < | | | | > | > > | | | | | | | | | | | < | | | | | | | | | | | | | | | | < | | | | | < | | | | | | | < | > | < | | | < < | > > < | | | | < < | | | > | | | | | | | | < < | < | < < | > > > > > > > > > > > | | | | | | | > | | > | < | | | | > | | | | | | | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | * Side effects: * The image and text are drawn. * *---------------------------------------------------------------------- */ void DrawMenuButtonImageAndText( TkMenuButton *butPtr) { MacMenuButton *mbPtr = (MacMenuButton *) butPtr; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; int haveImage = 0, haveText = 0; int imageWidth = 0, imageHeight = 0; int imageXOffset = 0, imageYOffset = 0; int textXOffset = 0, textYOffset = 0; int width = 0, height = 0; int fullWidth = 0, fullHeight = 0; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } DrawParams *dpPtr = &mbPtr->drawParams; pixmap = (Pixmap) Tk_WindowId(tkwin); if (butPtr->image != None) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); haveImage = 1; } imageWidth = width; imageHeight = height; haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { int x = 0, y = 0; textXOffset = 0; textYOffset = 0; fullWidth = 0; fullHeight = 0; switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: /* * Image is above or below text. */ if (butPtr->compound == COMPOUND_TOP) { textYOffset = height + butPtr->padY; } else { imageYOffset = butPtr->textHeight + butPtr->padY; } fullHeight = height + butPtr->textHeight + butPtr->padY; fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); textXOffset = (fullWidth - butPtr->textWidth)/2; imageXOffset = (fullWidth - width)/2; break; case COMPOUND_LEFT: case COMPOUND_RIGHT: /* * Image is left or right of text */ if (butPtr->compound == COMPOUND_LEFT) { textXOffset = width + butPtr->padX - 2; } else { imageXOffset = butPtr->textWidth + butPtr->padX; } fullWidth = butPtr->textWidth + butPtr->padX + width; fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); textYOffset = (fullHeight - butPtr->textHeight)/2; imageYOffset = (fullHeight - height)/2; break; case COMPOUND_CENTER: /* * Image and text are superimposed */ fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); textXOffset = (fullWidth - butPtr->textWidth) / 2; imageXOffset = (fullWidth - width) / 2; textYOffset = (fullHeight - butPtr->textHeight) / 2; imageYOffset = (fullHeight - height) / 2; break; case COMPOUND_NONE: break; } TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->inset, butPtr->padY + butPtr->inset, fullWidth, fullHeight, &x, &y); imageXOffset = LEFT_INSET; imageYOffset += y; textYOffset -= 1; if (butPtr->image != NULL) { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else { XSetClipOrigin(butPtr->display, dpPtr->gc, imageXOffset, imageYOffset); XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, 0, 0, (unsigned int) width, (unsigned int) height, imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, butPtr->underline); } else { int x, y; if (haveImage) { TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, width, height, &x, &y); imageXOffset = LEFT_INSET; imageYOffset += y; if (butPtr->image != NULL) { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); } else { XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, 0, 0, (unsigned int) width, (unsigned int) height, imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } } else { textXOffset = LEFT_INSET; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->textWidth, butPtr->textHeight, &x, &y); Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, textXOffset, y, 0, -1); y += butPtr->textHeight/2; } } } /* *-------------------------------------------------------------- * * TkMacOSXDrawMenuButton -- * * This function draws the tk menubutton using Mac controls. In * addition, this code may apply custom colors passed in the * TkMenubutton. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void TkMacOSXDrawMenuButton( MacMenuButton *mbPtr, /* Mac menubutton. */ GC gc, /* The GC we are drawing into - needed for the bevel * button */ Pixmap pixmap) /* The pixmap we are drawing into - needed for the * bevel button */ { TkMenuButton *butPtr = (TkMenuButton *) mbPtr; TkWindow *winPtr = (TkWindow *) butPtr->tkwin; HIRect cntrRect; TkMacOSXDrawingContext dc; DrawParams *dpPtr = &mbPtr->drawParams; int useNewerHITools = 1; TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin), Tk_Height(butPtr->tkwin)); if (useNewerHITools == 1) { HIRect contHIRec; static HIThemeButtonDrawInfo hiinfo; MenuButtonBackgroundDrawCB(mbPtr, 32, true); if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } hiinfo.version = 0; hiinfo.state = mbPtr->drawinfo.state; hiinfo.kind = mbPtr->btnkind; hiinfo.value = mbPtr->drawinfo.value; hiinfo.adornment = mbPtr->drawinfo.adornment; hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent(); if (hiinfo.animation.time.start == 0) { hiinfo.animation.time.start = hiinfo.animation.time.current; } /* * To avoid menubuttons with white text on a white background, we * always set the state to inactive in Dark Mode. It isn't perfect but * it is usable. Using a ttk::menubutton would be a better choice, * however. */ if (TkMacOSXInDarkMode(butPtr->tkwin)) { hiinfo.state = kThemeStateInactive; } HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); MenuButtonContentDrawCB(mbPtr->btnkind, &mbPtr->drawinfo, mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } TkMacOSXRestoreDrawingContext(&dc); } mbPtr->lastdrawinfo = mbPtr->drawinfo; } /* *-------------------------------------------------------------- * * MenuButtonBackgroundDrawCB -- * * This function draws the background that lies under checkboxes and * radiobuttons. * * Results: * None. * * Side effects: * The background gets updated to the current color. * *-------------------------------------------------------------- */ static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev) { TkMenuButton* butPtr = (TkMenuButton *) ptr; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } pixmap = (Pixmap) Tk_WindowId(tkwin); Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } /* *-------------------------------------------------------------- * * MenuButtonContentDrawCB -- * * This function draws the label and image for the button. * * Results: * None. * * Side effects: * The content of the button gets updated. * *-------------------------------------------------------------- */ static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo *drawinfo, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev) { TkMenuButton *butPtr = (TkMenuButton *) ptr; Tk_Window tkwin = butPtr->tkwin; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } DrawMenuButtonImageAndText(butPtr); } /* *-------------------------------------------------------------- * * MenuButtonEventProc -- * * This procedure is invoked by the Tk dispatcher for various events on * buttons. * * Results: * None. * * Side effects: * When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void MenuButtonEventProc( ClientData clientData, /* Information about window. */ XEvent *eventPtr) /* Information about event. */ { TkMenuButton *buttonPtr = clientData; MacMenuButton *mbPtr = clientData; if (eventPtr->type == ActivateNotify || eventPtr->type == DeactivateNotify) { if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) { return; } if (eventPtr->type == ActivateNotify) { |
︙ | ︙ | |||
721 722 723 724 725 726 727 | } /* *---------------------------------------------------------------------- * * TkMacOSXComputeMenuButtonParams -- * | | | | | | | | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | } /* *---------------------------------------------------------------------- * * TkMacOSXComputeMenuButtonParams -- * * This procedure computes the various parameters used when creating a * Carbon Appearance control. These are determined by the various Tk * button parameters * * Results: * None. * * Side effects: * Sets the btnkind and drawinfo parameters * *---------------------------------------------------------------------- */ static void TkMacOSXComputeMenuButtonParams( TkMenuButton *butPtr, ThemeButtonKind *btnkind, HIThemeButtonDrawInfo *drawinfo) { MacMenuButton *mbPtr = (MacMenuButton *) butPtr; if (butPtr->image || butPtr->bitmap || butPtr->text) { /* TODO: allow for Small and Mini menubuttons. */ *btnkind = kThemePopupButton; } else { /* This should never happen. */ *btnkind = kThemeArrowButton; } |
︙ | ︙ | |||
785 786 787 788 789 790 791 | } /* *---------------------------------------------------------------------- * * TkMacOSXComputeMenuButtonDrawParams -- * | | | | | | | | | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | } /* *---------------------------------------------------------------------- * * TkMacOSXComputeMenuButtonDrawParams -- * * This procedure selects an appropriate drawing context for drawing a * menubutton. * * Results: * None. * * Side effects: * Sets the button draw parameters. * *---------------------------------------------------------------------- */ static void TkMacOSXComputeMenuButtonDrawParams( TkMenuButton *butPtr, DrawParams *dpPtr) { dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { dpPtr->gc = butPtr->disabledGC; } else if (butPtr->state == STATE_ACTIVE) { dpPtr->gc = butPtr->activeTextGC; dpPtr->border = butPtr->activeBorder; } else { dpPtr->gc = butPtr->normalTextGC; } } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXMenus.c.
︙ | ︙ | |||
173 174 175 176 177 178 179 | } - (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>) anItem { SEL action = [anItem action]; if (sel_isEqual(action, @selector(preferences:))) { | < | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | } - (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>) anItem { SEL action = [anItem action]; if (sel_isEqual(action, @selector(preferences:))) { return (_eventInterp && Tcl_FindCommand(_eventInterp, "::tk::mac::ShowPreferences", NULL, 0)); } else if (sel_isEqual(action, @selector(tkDemo:))) { BOOL haveDemo = NO; if (_eventInterp) { Tcl_Obj *path = GetWidgetDemoPath(_eventInterp); |
︙ | ︙ | |||
318 319 320 321 322 323 324 | *---------------------------------------------------------------------- */ static Tcl_Obj * GetWidgetDemoPath( Tcl_Interp *interp) { | | | | < | > | < < > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | *---------------------------------------------------------------------- */ static Tcl_Obj * GetWidgetDemoPath( Tcl_Interp *interp) { Tcl_Obj *result = NULL; if (Tcl_EvalEx(interp, "::tk::pkgconfig get demodir,runtime", -1, TCL_EVAL_GLOBAL) == TCL_OK) { Tcl_Obj *libpath, *demo[1] = { Tcl_NewStringObj("widget", 6) }; libpath = Tcl_GetObjResult(interp); Tcl_IncrRefCount(libpath); result = Tcl_FSJoinToPath(libpath, 1, demo); Tcl_DecrRefCount(libpath); } Tcl_ResetResult(interp); return result; } /* *---------------------------------------------------------------------- * * TkMacOSXHandleMenuSelect -- |
︙ | ︙ |
Changes to macosx/tkMacOSXMouseEvent.c.
︙ | ︙ | |||
240 241 242 243 244 245 246 | tkwin, global.x, global.y, state); #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); } else { /* * For scroll wheel events we need to send the XEvent here. */ | | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | tkwin, global.x, global.y, state); #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); } else { /* * For scroll wheel events we need to send the XEvent here. */ CGFloat delta; int coarseDelta; XEvent xEvent; xEvent.type = MouseWheelEvent; xEvent.xbutton.x = local.x; xEvent.xbutton.y = local.y; |
︙ | ︙ |
Changes to macosx/tkMacOSXNotify.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)) static void TkMacOSXNotifyExitHandler(ClientData clientData); static void TkMacOSXEventsSetupProc(ClientData clientData, int flags); static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); #ifdef TK_MAC_DEBUG_EVENTS | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)) static void TkMacOSXNotifyExitHandler(ClientData clientData); static void TkMacOSXEventsSetupProc(ClientData clientData, int flags); static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); #ifdef TK_MAC_DEBUG_EVENTS static const char *Tk_EventName[39] = { "", "", "KeyPress", /*2*/ "KeyRelease", /*3*/ "ButtonPress", /*4*/ "ButtonRelease", /*5*/ "MotionNotify", /*6*/ |
︙ | ︙ | |||
132 133 134 135 136 137 138 | * no longer, and perhaps never did need to set autoDisplay to NO, nor call * displayIfNeeded on our windows. We can just leave all of that to the window * manager. */ /* * Since the contentView is the first responder for a Tk Window, it is | | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | * no longer, and perhaps never did need to set autoDisplay to NO, nor call * displayIfNeeded on our windows. We can just leave all of that to the window * manager. */ /* * Since the contentView is the first responder for a Tk Window, it is * responsible for sending events up the responder chain. We also check the * pasteboard here. */ - (void) sendEvent: (NSEvent *) theEvent { [super sendEvent:theEvent]; [NSApp tkCheckPasteboard]; #ifdef TK_MAC_DEBUG_EVENTS fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]); |
︙ | ︙ | |||
186 187 188 189 190 191 192 | } /* *---------------------------------------------------------------------- * * Tk_MacOSXSetupTkNotifier -- * | | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | } /* *---------------------------------------------------------------------- * * Tk_MacOSXSetupTkNotifier -- * * This procedure is called during Tk initialization to create the event * source for TkAqua events. * * Results: * None. * * Side effects: * A new event source is created. * |
︙ | ︙ | |||
220 221 222 223 224 225 226 | * Panic if main runloop is not on the main application thread. */ Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s", "first [load] of TkAqua has to occur in the main thread!"); } Tcl_CreateEventSource(TkMacOSXEventsSetupProc, | | < | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | * Panic if main runloop is not on the main application thread. */ Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s", "first [load] of TkAqua has to occur in the main thread!"); } Tcl_CreateEventSource(TkMacOSXEventsSetupProc, TkMacOSXEventsCheckProc, NULL); TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); Tcl_SetServiceMode(TCL_SERVICE_ALL); TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode); TclMacOSXNotifierAddRunLoopMode(NSModalPanelRunLoopMode); } } } |
︙ | ︙ | |||
254 255 256 257 258 259 260 | static void TkMacOSXNotifyExitHandler( ClientData clientData) /* Not used. */ { TSD_INIT(); Tcl_DeleteEventSource(TkMacOSXEventsSetupProc, | | < | | | | | | | > > | > > > > | > > > | | | | | | | | > > | > > > > | > | | | | > > | > > | | | > | > > < > > | > > < | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | static void TkMacOSXNotifyExitHandler( ClientData clientData) /* Not used. */ { TSD_INIT(); Tcl_DeleteEventSource(TkMacOSXEventsSetupProc, TkMacOSXEventsCheckProc, NULL); tsdPtr->initialized = 0; } /* *---------------------------------------------------------------------- * * TkMacOSXEventsSetupProc -- * * This procedure implements the setup part of the MacOSX event source. It * is invoked by Tcl_DoOneEvent before calling TkMacOSXEventsProc to * process all queued NSEvents. In our case, all we need to do is to set * the Tcl MaxBlockTime to 0 before starting the loop to process all * queued NSEvents. * * Results: * None. * * Side effects: * * If NSEvents are queued, then the maximum block time will be set to 0 to * ensure that control returns immediately to Tcl. * *---------------------------------------------------------------------- */ static void TkMacOSXEventsSetupProc( ClientData clientData, int flags) { NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; /* * runloopMode will be nil if we are in a Tcl event loop. */ if (flags & TCL_WINDOW_EVENTS && !runloopMode) { static const Tcl_Time zeroBlockTime = { 0, 0 }; [NSApp _resetAutoreleasePool]; /* * Call this with dequeue=NO -- just checking if the queue is empty. */ NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; if (currentEvent) { if (currentEvent.type > 0) { Tcl_SetMaxBlockTime(&zeroBlockTime); } } } } /* *---------------------------------------------------------------------- * * TkMacOSXEventsCheckProc -- * * This procedure loops through all NSEvents waiting in the TKApplication * event queue, generating X events from them. * * Results: * None. * * Side effects: * NSevents are used to generate X events, which are added to the Tcl * event queue. * *---------------------------------------------------------------------- */ static void TkMacOSXEventsCheckProc( ClientData clientData, int flags) { NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; /* * runloopMode will be nil if we are in a Tcl event loop. */ if (flags & TCL_WINDOW_EVENTS && !runloopMode) { NSEvent *currentEvent = nil; NSEvent *testEvent = nil; NSModalSession modalSession; /* * It is possible for the SetupProc to be called before this function * returns. This happens, for example, when we process an event which * opens a modal window. To prevent premature release of our * application-wide autorelease pool by a nested call to the SetupProc, * we must lock it here. */ [NSApp _lockAutoreleasePool]; do { modalSession = TkMacOSXGetModalSession(); testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) dequeue:NO]; /* * We must not steal any events during LiveResize. */ if (testEvent && [[testEvent window] inLiveResize]) { break; } currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) dequeue:YES]; if (currentEvent) { /* * Generate Xevents. */ int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; Tcl_SetServiceMode(oldServiceMode); if (processedEvent) { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@" event: %@", currentEvent); #endif if (modalSession) { [NSApp _modalSession:modalSession sendEvent:currentEvent]; } else { [NSApp sendEvent:currentEvent]; } } } else { break; } } while (1); /* * Now we can unlock the pool. */ [NSApp _unlockAutoreleasePool]; } } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXPrivate.h.
︙ | ︙ | |||
229 230 231 232 233 234 235 236 237 238 239 240 241 242 | NSWindow *macWindow); MODULE_SCOPE int TkMacOSXStandardAboutPanelObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TkMacOSXIconBitmapObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #pragma mark Private Objective-C Classes #define VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) enum { tkMainMenu = 1, tkApplicationMenu, tkWindowsMenu, tkHelpMenu}; | > > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | NSWindow *macWindow); MODULE_SCOPE int TkMacOSXStandardAboutPanelObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TkMacOSXIconBitmapObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE void TkMacOSXDrawSolidBorder(Tk_Window tkwin, GC gc, int inset, int thickness); #pragma mark Private Objective-C Classes #define VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) enum { tkMainMenu = 1, tkApplicationMenu, tkWindowsMenu, tkHelpMenu}; |
︙ | ︙ | |||
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | - (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent; @end VISIBILITY_HIDDEN @interface TKContentView : NSView <NSTextInput> { NSString *privateWorkingText; } @end @interface TKContentView(TKKeyEvent) - (void) deleteWorkingText; @end @interface TKContentView(TKWindowEvent) | > > > > > > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | - (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent; @end VISIBILITY_HIDDEN @interface TKContentView : NSView <NSTextInput> { @private NSString *privateWorkingText; #ifdef __i386__ /* The Objective C runtime used on i386 requires this. */ Bool _needsRedisplay; #endif } @property Bool needsRedisplay; @end @interface TKContentView(TKKeyEvent) - (void) deleteWorkingText; @end @interface TKContentView(TKWindowEvent) |
︙ | ︙ |
Changes to macosx/tkMacOSXRegion.c.
︙ | ︙ | |||
183 184 185 186 187 188 189 | * * TkRectInRegion -- * * Implements the equivelent of the X window function XRectInRegion. See * Xwindow documentation for more details. * * Results: | | | | | < | > | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | * * TkRectInRegion -- * * Implements the equivelent of the X window function XRectInRegion. See * Xwindow documentation for more details. * * Results: * Returns RectanglePart or RectangleOut. Note that this is not a complete * implementation since it doesn't test for RectangleIn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TkRectInRegion( TkRegion region, int x, int y, unsigned int width, unsigned int height) { if (TkMacOSXIsEmptyRegion(region)) { return RectangleOut; } else { const CGRect r = CGRectMake(x, y, width, height); return HIShapeIntersectsRect((HIShapeRef) region, &r) ? RectanglePart : RectangleOut; } } /* *---------------------------------------------------------------------- * * TkClipBox -- |
︙ | ︙ | |||
230 231 232 233 234 235 236 | * *---------------------------------------------------------------------- */ void TkClipBox( TkRegion r, | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | * *---------------------------------------------------------------------- */ void TkClipBox( TkRegion r, XRectangle *rect_return) { CGRect rect; HIShapeGetBounds((HIShapeRef) r, &rect); rect_return->x = rect.origin.x; rect_return->y = rect.origin.y; rect_return->width = rect.size.width; |
︙ | ︙ |
Changes to macosx/tkMacOSXScale.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 | */ static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */ /* * Forward declarations for procedures defined later in this file: */ | | > | | < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | */ static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */ /* * Forward declarations for procedures defined later in this file: */ static void MacScaleEventProc(ClientData clientData, XEvent *eventPtr); static pascal void ScaleActionProc(ControlRef theControl, ControlPartCode partCode); /* *---------------------------------------------------------------------- * * TkpCreateScale -- * * Allocate a new TkScale structure. |
︙ | ︙ | |||
80 81 82 83 84 85 86 | macScalePtr->scaleHandle = NULL; if (scaleActionProc == NULL) { scaleActionProc = NewControlActionUPP(ScaleActionProc); } Tk_CreateEventHandler(tkwin, ButtonPressMask, | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | macScalePtr->scaleHandle = NULL; if (scaleActionProc == NULL) { scaleActionProc = NewControlActionUPP(ScaleActionProc); } Tk_CreateEventHandler(tkwin, ButtonPressMask, MacScaleEventProc, macScalePtr); return (TkScale *) macScalePtr; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
121 122 123 124 125 126 127 | } /* *---------------------------------------------------------------------- * * TkpDisplayScale -- * | | | | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | } /* *---------------------------------------------------------------------- * * TkpDisplayScale -- * * This procedure is invoked as an idle handler to redisplay the contents * of a scale widget. * * Results: * None. * * Side effects: * The scale gets redisplayed. * *---------------------------------------------------------------------- */ void TkpDisplayScale( ClientData clientData) /* Widget record for scale. */ { TkScale *scalePtr = clientData; Tk_Window tkwin = scalePtr->tkwin; Tcl_Interp *interp = scalePtr->interp; int result; char string[TCL_DOUBLE_SPACE]; MacScale *macScalePtr = clientData; Rect r; WindowRef windowRef; CGrafPtr destPort, savePort; Boolean portChanged; MacDrawable *macDraw; SInt32 initialValue, minValue, maxValue; UInt16 numTicks; |
︙ | ︙ | |||
164 165 166 167 168 169 170 | goto done; } /* * Invoke the scale's command if needed. */ | | | | | | | | < | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | goto done; } /* * Invoke the scale's command if needed. */ Tcl_Preserve(scalePtr); if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) { Tcl_Preserve(interp); if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format, scalePtr->value) < 0) { string[TCL_DOUBLE_SPACE - 1] = '\0'; } Tcl_DStringInit(&buf); Tcl_DStringAppend(&buf, scalePtr->command, -1); Tcl_DStringAppend(&buf, " ", -1); Tcl_DStringAppend(&buf, string, -1); result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); Tcl_DStringFree(&buf); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (command executed by scale)"); Tcl_BackgroundException(interp, result); } Tcl_Release(interp); } scalePtr->flags &= ~INVOKE_COMMAND; if (scalePtr->flags & SCALE_DELETED) { Tcl_Release(scalePtr); return; } Tcl_Release(scalePtr); /* * Now handle the part of redisplay that is the same for horizontal and * vertical scales: border and traversal highlight. */ if (scalePtr->highlightWidth != 0) { GC gc = Tk_GCForColor(scalePtr->highlightColorPtr, Tk_WindowId(tkwin)); Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, Tk_WindowId(tkwin)); |
︙ | ︙ | |||
225 226 227 228 229 230 231 | /* * Create Macintosh control. */ #define MAC_OSX_SCROLL_WIDTH 10 if (scalePtr->orient == ORIENT_HORIZONTAL) { | | | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | /* * Create Macintosh control. */ #define MAC_OSX_SCROLL_WIDTH 10 if (scalePtr->orient == ORIENT_HORIZONTAL) { int offset = (Tk_Height(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2; if (offset < 0) { offset = 0; } r.left = macDraw->xOff + scalePtr->inset; r.top = macDraw->yOff + offset; r.right = macDraw->xOff+Tk_Width(tkwin) - scalePtr->inset; r.bottom = macDraw->yOff + offset + MAC_OSX_SCROLL_WIDTH/2; } else { int offset = (Tk_Width(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2; if (offset < 0) { offset = 0; } r.left = macDraw->xOff + offset; r.top = macDraw->yOff + scalePtr->inset; r.right = macDraw->xOff + offset + MAC_OSX_SCROLL_WIDTH/2; r.bottom = macDraw->yOff + Tk_Height(tkwin) - scalePtr->inset; } if (macScalePtr->scaleHandle == NULL) { #ifdef TK_MAC_DEBUG_SCALE TkMacOSXDbgMsg("Initialising scale"); #endif initialValue = scalePtr->value; |
︙ | ︙ | |||
269 270 271 272 273 274 275 | numTicks = 0; } else { numTicks = (maxValue - minValue)/scalePtr->tickInterval; } CreateSliderControl(windowRef, &r, initialValue, minValue, maxValue, kControlSliderPointsDownOrRight, numTicks, 1, scaleActionProc, | | | | | < | | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | numTicks = 0; } else { numTicks = (maxValue - minValue)/scalePtr->tickInterval; } CreateSliderControl(windowRef, &r, initialValue, minValue, maxValue, kControlSliderPointsDownOrRight, numTicks, 1, scaleActionProc, &macScalePtr->scaleHandle); SetControlReference(macScalePtr->scaleHandle, (UInt32) scalePtr); if (IsWindowActive(windowRef)) { macScalePtr->flags |= ACTIVE; } } else { SetControlBounds(macScalePtr->scaleHandle, &r); SetControl32BitValue(macScalePtr->scaleHandle, scalePtr->value); SetControl32BitMinimum(macScalePtr->scaleHandle, scalePtr->fromValue); SetControl32BitMaximum(macScalePtr->scaleHandle, scalePtr->toValue); } /* * Finally draw the control. */ SetControlVisibility(macScalePtr->scaleHandle, true, true); HiliteControl(macScalePtr->scaleHandle, 0); Draw1Control(macScalePtr->scaleHandle); if (portChanged) { QDSwapPort(savePort, NULL); } done: scalePtr->flags &= ~REDRAW_ALL; } /* *---------------------------------------------------------------------- * * TkpScaleElement -- * * Determine which part of a scale widget lies under a given point. * * Results: * The return value is either TROUGH1, SLIDER, TROUGH2, or OTHER, * depending on which of the scale's active elements (if any) is under the * point at (x,y). * * Side effects: * None. * *---------------------------------------------------------------------- */ |
︙ | ︙ | |||
353 354 355 356 357 358 359 | } #ifdef TK_MAC_DEBUG_SCALE fprintf (stderr,"ScalePart %d, pos ( %d %d )\n", part, where.h, where.v ); #endif switch (part) { | | | | | | | | | | | | | | | | | | | | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | } #ifdef TK_MAC_DEBUG_SCALE fprintf (stderr,"ScalePart %d, pos ( %d %d )\n", part, where.h, where.v ); #endif switch (part) { case inSlider: return SLIDER; case inInc: if (scalePtr->orient == ORIENT_VERTICAL) { return TROUGH1; } else { return TROUGH2; } case inDecr: if (scalePtr->orient == ORIENT_VERTICAL) { return TROUGH2; } else { return TROUGH1; } default: return OTHER; } } /* *-------------------------------------------------------------- * * MacScaleEventProc -- * * This procedure is invoked by the Tk dispatcher for ButtonPress 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 MacScaleEventProc( ClientData clientData, /* Information about window. */ |
︙ | ︙ | |||
407 408 409 410 411 412 413 | Boolean portChanged; #ifdef TK_MAC_DEBUG_SCALE fprintf(stderr,"MacScaleEventProc\n" ); #endif /* | | | | | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | Boolean portChanged; #ifdef TK_MAC_DEBUG_SCALE fprintf(stderr,"MacScaleEventProc\n" ); #endif /* * To call Macintosh control routines we must have the port set to the * window containing the control. We will then test which part of the * control was hit and act accordingly. */ destPort = TkMacOSXGetDrawablePort(Tk_WindowId(macScalePtr->info.tkwin)); portChanged = QDSwapPort(destPort, &savePort); TkMacOSXSetUpClippingRgn(Tk_WindowId(macScalePtr->info.tkwin)); TkMacOSXWinBounds((TkWindow *) macScalePtr->info.tkwin, &bounds); |
︙ | ︙ | |||
457 458 459 460 461 462 463 | /* *-------------------------------------------------------------- * * ScaleActionProc -- * * Callback procedure used by the Macintosh toolbox call | | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | /* *-------------------------------------------------------------- * * ScaleActionProc -- * * Callback procedure used by the Macintosh toolbox call * HandleControlClick. This call will update the display while the * scrollbar is being manipulated by the user. * * Results: * None. * * Side effects: * May change the display. * |
︙ | ︙ | |||
482 483 484 485 486 487 488 | TkScale *scalePtr = (TkScale *) GetControlReference(theControl); #ifdef TK_MAC_DEBUG_SCALE TkMacOSXDbgMsg("ScaleActionProc"); #endif value = GetControlValue(theControl); TkScaleSetValue(scalePtr, value, 1, 1); | | | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | TkScale *scalePtr = (TkScale *) GetControlReference(theControl); #ifdef TK_MAC_DEBUG_SCALE TkMacOSXDbgMsg("ScaleActionProc"); #endif value = GetControlValue(theControl); TkScaleSetValue(scalePtr, value, 1, 1); Tcl_Preserve(scalePtr); TkMacOSXRunTclEventLoop(); Tcl_Release(scalePtr); } #endif /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXScrlbr.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC. * Copyright (c) 2018 Marc Culler * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkScrollbar.h" #include "tkMacOSXPrivate.h" | > < > | > > | | | | | | | | | > > < | < | > | > | | | < | | | | | | | | | | | | | | | | | > | | | | > > | > > > | > > | | | | | | | | > | > > > | > | | < < | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | /* * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC. * Copyright (c) 2018 Marc Culler * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkScrollbar.h" #include "tkMacOSXPrivate.h" #define MIN_SCROLLBAR_VALUE 0 /* * Minimum slider length, in pixels (designed to make sure that the slider is * always easy to grab with the mouse). */ #define MIN_SLIDER_LENGTH 5 /* * Borrowed from ttkMacOSXTheme.c to provide appropriate scaling. */ #ifdef __LP64__ #define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum)) #else #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ /* * Apple reversed the scroll direction with the release of OSX 10.7 Lion. */ #define SNOW_LEOPARD_STYLE (NSAppKitVersionNumber < 1138) /* * Declaration of an extended scrollbar structure with Mac specific additions. */ typedef struct MacScrollbar { TkScrollbar information; /* Generic scrollbar info. */ GC troughGC; /* For drawing trough. */ GC copyGC; /* Used for copying from pixmap onto screen. */ Bool buttonDown; /* Is the mouse button down? */ Bool mouseOver; /* Is the pointer over the scrollbar. */ HIThemeTrackDrawInfo info; /* Controls how the scrollbar is drawn. */ } MacScrollbar; /* Used to initialize a MacScrollbar's info field. */ HIThemeTrackDrawInfo defaultInfo = { .version = 0, .min = 0.0, .max = 100.0, .attributes = kThemeTrackShowThumb, }; /* * The class procedure table for the scrollbar widget. All fields except size * are left initialized to NULL, which should happen automatically since the * variable is declared at this scope. */ const Tk_ClassProcs tkpScrollbarProcs = { sizeof(Tk_ClassProcs), /* size */ NULL, /* worldChangedProc */ NULL, /* createProc */ NULL /* modalProc */ }; /* * Information on scrollbar layout, metrics, and draw info. */ typedef struct ScrollbarMetrics { SInt32 width, minThumbHeight; int minHeight, topArrowHeight, bottomArrowHeight; NSControlSize controlSize; } ScrollbarMetrics; static ScrollbarMetrics metrics = { 15, 54, 26, 14, 14, kControlSizeNormal /* kThemeScrollBarMedium */ }; /* * Declarations of static functions defined later in this file: */ static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); static int ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr); static void UpdateControlValues(TkScrollbar *scrollPtr); /* *---------------------------------------------------------------------- * * TkpCreateScrollbar -- * * Allocate a new TkScrollbar structure. * * Results: * Returns a newly allocated TkScrollbar structure. * * Side effects: * Registers an event handler for the widget. * *---------------------------------------------------------------------- */ TkScrollbar * TkpCreateScrollbar( Tk_Window tkwin) { MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar)); scrollPtr->troughGC = NULL; scrollPtr->copyGC = NULL; scrollPtr->info = defaultInfo; scrollPtr->buttonDown = false; Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask, ScrollbarEventProc, scrollPtr); return (TkScrollbar *) scrollPtr; } /* *-------------------------------------------------------------- * * TkpDisplayScrollbar -- * * This procedure redraws the contents of a scrollbar 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: * Draws a scrollbar on the screen. * *-------------------------------------------------------------- */ void TkpDisplayScrollbar( ClientData clientData) /* Information about window. */ { register TkScrollbar *scrollPtr = clientData; MacScrollbar *msPtr = (MacScrollbar *) scrollPtr; register Tk_Window tkwin = scrollPtr->tkwin; TkWindow *winPtr = (TkWindow *) tkwin; TkMacOSXDrawingContext dc; scrollPtr->flags &= ~REDRAW_PENDING; if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } MacDrawable *macWin = (MacDrawable *) winPtr->window; NSView *view = TkMacOSXDrawableView(macWin); if ((view == NULL) || (macWin->flags & TK_DO_NOT_DRAW) || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { return; } CGFloat viewHeight = [view bounds].size.height; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight }; CGContextConcatCTM(dc.context, t); /* * Draw a 3D rectangle to provide a base for the native scrollbar. */ if (scrollPtr->highlightWidth != 0) { GC fgGC, bgGC; bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin); if (scrollPtr->flags & GOT_FOCUS) { fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin); } else { fgGC = bgGC; } TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, (Pixmap) macWin); } Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, scrollPtr->borderWidth, scrollPtr->relief); Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->inset, scrollPtr->inset, Tk_Width(tkwin) - 2*scrollPtr->inset, Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT); /* * Update values and then draw the native scrollbar over the rectangle. */ UpdateControlValues(scrollPtr); if (SNOW_LEOPARD_STYLE) { HIThemeDrawTrack(&msPtr->info, 0, dc.context, kHIThemeOrientationInverted); } else { HIThemeDrawTrack(&msPtr->info, 0, dc.context, kHIThemeOrientationNormal); } TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; } /* *---------------------------------------------------------------------- * * TkpComputeScrollbarGeometry -- * * After changes in a scrollbar's size or configuration, this procedure * recomputes various geometry information used in displaying the * scrollbar. * * Results: * None. * * Side effects: * The scrollbar will be displayed differently. * *---------------------------------------------------------------------- */ extern void TkpComputeScrollbarGeometry( register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may have * changed. */ { /* * The code below is borrowed from tkUnixScrlbr.c but has been adjusted to * account for some differences between macOS and X11. The Unix scrollbar * has an arrow button on each end. On macOS 10.6 (Snow Leopard) the * scrollbars by default have both arrow buttons at the bottom or right. * (There is a preferences setting to use the Unix layout, but we are not * supporting that!) On more recent versions of macOS there are no arrow * buttons at all. The case of no arrow buttons can be handled as a special * case of having both buttons at the end, but where scrollPtr->arrowLength * happens to be zero. To adjust for having both arrows at the same end we * shift the scrollbar up by the arrowLength. */ int fieldLength; if (scrollPtr->highlightWidth < 0) { scrollPtr->highlightWidth = 0; } scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; if ([NSApp macMinorVersion] == 6) { scrollPtr->arrowLength = scrollPtr->width; } else { scrollPtr->arrowLength = 0; } fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) : Tk_Width(scrollPtr->tkwin)) - 2*(scrollPtr->arrowLength + scrollPtr->inset); if (fieldLength < 0) { fieldLength = 0; } scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction; scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction; /* * Adjust the slider so that some piece of it is always displayed in the * scrollbar and so that it has at least a minimal width (so it can be * grabbed with the mouse). */ if (scrollPtr->sliderFirst > fieldLength - MIN_SLIDER_LENGTH) { scrollPtr->sliderFirst = fieldLength - MIN_SLIDER_LENGTH; } if (scrollPtr->sliderFirst < 0) { scrollPtr->sliderFirst = 0; } if (scrollPtr->sliderLast < scrollPtr->sliderFirst + MIN_SLIDER_LENGTH) { scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH; } if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } scrollPtr->sliderFirst += -scrollPtr->arrowLength + scrollPtr->inset; scrollPtr->sliderLast += scrollPtr->inset; /* * Register the desired geometry for the window. Leave enough space for the * two arrows, if there are any arrows, plus a minimum-size slider, plus * border around the whole window, if any. Then arrange for the window to * be redisplayed. */ if (scrollPtr->vertical) { Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2*scrollPtr->inset, 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics.minThumbHeight); } else { Tk_GeometryRequest(scrollPtr->tkwin, 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics.minThumbHeight, scrollPtr->width + 2*scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); } /* *---------------------------------------------------------------------- * * TkpDestroyScrollbar -- * * Free data structures associated with the scrollbar control. * * Results: * None. * * Side effects: * Frees the GCs associated with the scrollbar. * *---------------------------------------------------------------------- */ void TkpDestroyScrollbar( TkScrollbar *scrollPtr) { MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; if (macScrollPtr->troughGC != None) { Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC); } if (macScrollPtr->copyGC != None) { Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC); } } /* *---------------------------------------------------------------------- * * TkpConfigureScrollbar -- * * This procedure is called after the generic code has finished processing * configuration options, in order to configure platform specific options. * There are no such option on the Mac, however. * * Results: * None. * * Side effects: * Currently, none. * *---------------------------------------------------------------------- */ void TkpConfigureScrollbar( register TkScrollbar *scrollPtr) { /* empty */ } /* *-------------------------------------------------------------- * * TkpScrollbarPosition -- * * Determine the scrollbar element corresponding to a given position. * |
︙ | ︙ | |||
399 400 401 402 403 404 405 | int TkpScrollbarPosition( register TkScrollbar *scrollPtr, /* Scrollbar widget record. */ int x, int y) /* Coordinates within scrollPtr's window. */ { | < | | | | | | | | | | | | | | | | | | | | | > > | > > | | | | | | | | | < | | | > | | | | | | < < | | | | | > | > | | | | > | | < | | | | > > | > | | | | | | | | | | > | | | | > > | > > | > | > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | int TkpScrollbarPosition( register TkScrollbar *scrollPtr, /* Scrollbar widget record. */ int x, int y) /* Coordinates within scrollPtr's window. */ { /* * The code below is borrowed from tkUnixScrlbr.c and needs no adjustment * since it does not involve the arrow buttons. */ int length, width, tmp; register const int inset = scrollPtr->inset; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); width = Tk_Height(scrollPtr->tkwin); } if (x < inset || x >= width - inset || y < inset || y >= length - inset) { return OUTSIDE; } /* * Here we assume that the scrollbar is layed out with both arrow buttons * at the bottom (or right). Except on 10.6, however, the arrows do not * actually exist, i.e. the arrowLength is 0. These are the same * assumptions which are being made in TkpComputeScrollbarGeometry. */ if (y < scrollPtr->sliderFirst + scrollPtr->arrowLength) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } if (y < length - (2*scrollPtr->arrowLength + inset)) { return BOTTOM_GAP; } /* * On systems newer than 10.6 we have already returned. */ if (y < length - (scrollPtr->arrowLength + inset)) { return TOP_ARROW; } return BOTTOM_ARROW; } /* *-------------------------------------------------------------- * * UpdateControlValues -- * * This procedure updates the Macintosh scrollbar control to display the * values defined by the Tk scrollbar. This is the key interface to the * Mac-native scrollbar; the Unix bindings drive scrolling in the Tk * window and all the Mac scrollbar has to do is redraw itself. * * Results: * None. * * Side effects: * The Macintosh control is updated. * *-------------------------------------------------------------- */ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { MacScrollbar *msPtr = (MacScrollbar *) scrollPtr; Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; HIRect contrlRect; short width, height; NSView *view = TkMacOSXDrawableView(macWin); CGFloat viewHeight = [view bounds].size.height; NSRect frame; frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin), Tk_Height(tkwin)); frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset); frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); contrlRect = NSRectToCGRect(frame); msPtr->info.bounds = contrlRect; width = contrlRect.size.width; height = contrlRect.size.height; /* * Ensure we set scrollbar control bounds only once all size adjustments * have been computed. */ msPtr->info.bounds = contrlRect; if (scrollPtr->vertical) { msPtr->info.attributes &= ~kThemeTrackHorizontal; } else { msPtr->info.attributes |= kThemeTrackHorizontal; } /* * Given the Tk parameters for the fractions of the start and end of the * thumb, the following calculation determines the location for the * Macintosh thumb. The Aqua scroll control works as follows. The * scrollbar's value is the position of the left (or top) side of the view * area in the content area being scrolled. The maximum value of the * control is therefore the dimension of the content area less the size of * the view area. */ double maximum = 100, factor = RangeToFactor(maximum); dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction) * factor; msPtr->info.max = MIN_SCROLLBAR_VALUE + factor - dViewSize; msPtr->info.trackInfo.scrollbar.viewsize = dViewSize; if (scrollPtr->vertical) { if (SNOW_LEOPARD_STYLE) { msPtr->info.value = factor * scrollPtr->firstFraction; } else { msPtr->info.value = msPtr->info.max - factor * scrollPtr->firstFraction; } } else { msPtr->info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } if ((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0) || height <= metrics.minHeight) { msPtr->info.enableState = kThemeTrackHideTrack; } else { msPtr->info.enableState = kThemeTrackActive; msPtr->info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost; } } /* *-------------------------------------------------------------- * * ScrollbarEvent -- * * This procedure is invoked in response to <ButtonPress>, * <ButtonRelease>, <EnterNotify>, and <LeaveNotify> events. The * Scrollbar appearance is modified for each event. * *-------------------------------------------------------------- */ static int ScrollbarEvent( TkScrollbar *scrollPtr, XEvent *eventPtr) { MacScrollbar *msPtr = (MacScrollbar *) scrollPtr; /* * The pressState does not indicate whether the moused button was pressed * at some location in the Scrollbar. Rather, it indicates that the * scrollbar should appear as if it were pressed in that location. The * standard Mac behavior is that once the button is pressed inside the * Scrollbar the appearance should not change until the button is released, * even if the mouse moves outside of the scrollbar. However, if the mouse * lies over the scrollbar but the button is not pressed then the * appearance should be the same as if the button had been pressed on the * slider, i.e. kThemeThumbPressed. See the file Appearance.r, or * HIToolbox.bridgesupport on 10.14. */ if (eventPtr->type == ButtonPress) { msPtr->buttonDown = true; UpdateControlValues(scrollPtr); int where = TkpScrollbarPosition(scrollPtr, eventPtr->xbutton.x, eventPtr->xbutton.y); switch (where) { case OUTSIDE: msPtr->info.trackInfo.scrollbar.pressState = 0; break; case TOP_GAP: msPtr->info.trackInfo.scrollbar.pressState = kThemeTopTrackPressed; break; case SLIDER: msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed; break; case BOTTOM_GAP: msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomTrackPressed; break; case TOP_ARROW: /* * This looks wrong and the docs say it is wrong but it works. */ msPtr->info.trackInfo.scrollbar.pressState = kThemeTopInsideArrowPressed; break; case BOTTOM_ARROW: msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomOutsideArrowPressed; break; } } if (eventPtr->type == ButtonRelease) { msPtr->buttonDown = false; if (!msPtr->mouseOver) { msPtr->info.trackInfo.scrollbar.pressState = 0; |
︙ | ︙ | |||
618 619 620 621 622 623 624 | msPtr->mouseOver = false; if (!msPtr->buttonDown) { msPtr->info.trackInfo.scrollbar.pressState = 0; } } return TCL_OK; } | | < < | | | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | msPtr->mouseOver = false; if (!msPtr->buttonDown) { msPtr->info.trackInfo.scrollbar.pressState = 0; } } return TCL_OK; } /* *-------------------------------------------------------------- * * ScrollbarEventProc -- * * 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. * *-------------------------------------------------------------- */ static void ScrollbarEventProc( ClientData clientData, /* Information about window. */ XEvent *eventPtr) /* Information about event. */ { TkScrollbar *scrollPtr = clientData; switch (eventPtr->type) { case UnmapNotify: TkMacOSXSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false); break; |
︙ | ︙ | |||
664 665 666 667 668 669 670 | case LeaveNotify: ScrollbarEvent(clientData, eventPtr); break; default: TkScrollbarEventProc(clientData, eventPtr); } } | | | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | case LeaveNotify: ScrollbarEvent(clientData, eventPtr); break; default: TkScrollbarEventProc(clientData, eventPtr); } } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to macosx/tkMacOSXSend.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 | * list. */ } RegisteredInterp; /* * A registry of all interpreters for a display is kept in a property * "InterpRegistry" on the root window of the display. It is organized as a * series of zero or more concatenated strings (in no particular order), each | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | * list. */ } RegisteredInterp; /* * A registry of all interpreters for a display is kept in a property * "InterpRegistry" on the root window of the display. It is organized as a * series of zero or more concatenated strings (in no particular order), each * of the form: * window space name '\0' * where "window" is the hex id of the comm. window to use to talk to an * interpreter named "name". * * When the registry is being manipulated by an application (e.g. to add or * remove an entry), it is loaded into memory using a structure of the * following type: |
︙ | ︙ | |||
74 75 76 77 78 79 80 | * none. See format description above; this is * *not* terminated by the first null * character. Dynamically allocated. */ int allocedByX; /* Non-zero means must free property with * XFree; zero means use ckfree. */ } NameRegistry; | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | * none. See format description above; this is * *not* terminated by the first null * character. Dynamically allocated. */ int allocedByX; /* Non-zero means must free property with * XFree; zero means use ckfree. */ } NameRegistry; static int initialized = 0; /* A flag to denote if we have initialized * yet. */ static RegisteredInterp *interpListPtr = NULL; /* List of all interpreters registered by this * process. */ /* |
︙ | ︙ |
Changes to macosx/tkMacOSXSubwindows.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | * deleting is being tracked by the grab code. */ TkPointerDeadWindow(macWin->winPtr); TkMacOSXSelDeadWindow(macWin->winPtr); macWin->toplevel->referenceCount--; | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | * deleting is being tracked by the grab code. */ TkPointerDeadWindow(macWin->winPtr); TkMacOSXSelDeadWindow(macWin->winPtr); macWin->toplevel->referenceCount--; if (!Tk_IsTopLevel(macWin->winPtr)) { TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); if (macWin->winPtr->parentPtr != NULL) { TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr); } if (macWin->visRgn) { CFRelease(macWin->visRgn); } |
︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | void XMapWindow( Display *display, /* Display. */ Window window) /* Window. */ { MacDrawable *macWin = (MacDrawable *) window; XEvent event; /* * Under certain situations it's possible for this function to be called * before the toplevel window it's associated with has actually been * mapped. In that case we need to create the real Macintosh window now as * this function as well as other X functions assume that the portPtr is * valid. */ if (!TkMacOSXHostToplevelExists(macWin->toplevel->winPtr)) { TkMacOSXMakeRealWindowExist(macWin->toplevel->winPtr); } display->request++; | > > | | | < | | < | | | | | < < < < < < < < < > < | > | | < | | | | > > > > | < < < < < < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | void XMapWindow( Display *display, /* Display. */ Window window) /* Window. */ { MacDrawable *macWin = (MacDrawable *) window; TkWindow *winPtr = macWin->winPtr; NSWindow *win = TkMacOSXDrawableWindow(window); XEvent event; /* * Under certain situations it's possible for this function to be called * before the toplevel window it's associated with has actually been * mapped. In that case we need to create the real Macintosh window now as * this function as well as other X functions assume that the portPtr is * valid. */ if (!TkMacOSXHostToplevelExists(macWin->toplevel->winPtr)) { TkMacOSXMakeRealWindowExist(macWin->toplevel->winPtr); } display->request++; winPtr->flags |= TK_MAPPED; if (Tk_IsTopLevel(winPtr)) { if (!Tk_IsEmbedded(winPtr)) { /* * We want to activate Tk when a toplevel is mapped but we must not * supply YES here. This is because during Tk initialization the * root window is mapped before applicationDidFinishLaunching * returns. Forcing the app to activate too early can make the menu * bar unresponsive. */ TkMacOSXApplyWindowAttributes(winPtr, win); [win setExcludedFromWindowsMenu:NO]; [NSApp activateIgnoringOtherApps:NO]; [[win contentView] setNeedsDisplay:YES]; if ([win canBecomeKeyWindow]) { [win makeKeyAndOrderFront:NSApp]; } else { [win orderFrontRegardless]; } } else { TkWindow *contWinPtr = TkpGetOtherWindow(winPtr); /* * Rebuild the container's clipping region and display * the window. */ TkMacOSXInvalClipRgns((Tk_Window) contWinPtr); TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); } TkMacOSXInvalClipRgns((Tk_Window) winPtr); /* * We only need to send the MapNotify event for toplevel windows. */ event.xany.serial = LastKnownRequestProcessed(display); event.xany.send_event = False; event.xany.display = display; event.xmap.window = window; event.xmap.type = MapNotify; event.xmap.event = window; event.xmap.override_redirect = winPtr->atts.override_redirect; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } else { /* * For non-toplevel windows, rebuild the parent's clipping region * and redisplay the window. */ TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); if ([NSApp isDrawing]) { [[win contentView] setNeedsRedisplay:YES]; } else { [[win contentView] setNeedsDisplay:YES]; } } /* * Generate VisibilityNotify events for window and all mapped children. */ event.xany.send_event = False; event.xany.display = display; event.xvisibility.type = VisibilityNotify; event.xvisibility.state = VisibilityUnobscured; NotifyVisibility(winPtr, &event); } /* *---------------------------------------------------------------------- * * NotifyVisibility -- * |
︙ | ︙ | |||
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | XEvent event; display->request++; if (Tk_IsTopLevel(winPtr)) { if (!Tk_IsEmbedded(winPtr) && winPtr->wmInfoPtr->hints.initial_state!=IconicState) { NSWindow *win = TkMacOSXDrawableWindow(window); [win orderOut:nil]; } TkMacOSXInvalClipRgns((Tk_Window) winPtr); /* * We only need to send the UnmapNotify event for toplevel windows. */ event.xany.serial = LastKnownRequestProcessed(display); event.xany.send_event = False; event.xany.display = display; event.xunmap.type = UnmapNotify; event.xunmap.window = window; event.xunmap.event = window; event.xunmap.from_configure = false; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } else { | > < | > | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | XEvent event; display->request++; if (Tk_IsTopLevel(winPtr)) { if (!Tk_IsEmbedded(winPtr) && winPtr->wmInfoPtr->hints.initial_state!=IconicState) { NSWindow *win = TkMacOSXDrawableWindow(window); [win orderOut:nil]; } TkMacOSXInvalClipRgns((Tk_Window) winPtr); /* * We only need to send the UnmapNotify event for toplevel windows. */ event.xany.serial = LastKnownRequestProcessed(display); event.xany.send_event = False; event.xany.display = display; event.xunmap.type = UnmapNotify; event.xunmap.window = window; event.xunmap.event = window; event.xunmap.from_configure = false; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } else { /* * Rebuild the visRgn clip region for the parent so it will be allowed * to draw in the space from which this subwindow was removed. */ if (parentPtr && parentPtr->privatePtr->visRgn) { TkMacOSXInvalidateViewRegion( TkMacOSXDrawableView(parentPtr->privatePtr), parentPtr->privatePtr->visRgn); } TkMacOSXInvalClipRgns((Tk_Window) parentPtr); TkMacOSXUpdateClipRgn(parentPtr); } winPtr->flags &= ~TK_MAPPED; } |
︙ | ︙ | |||
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | XResizeWindow( Display *display, /* Display. */ Window window, /* Window. */ unsigned int width, unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { NSRect r = [w contentRectForFrameRect:[w frame]]; r.origin.y += r.size.height - height; r.size.width = width; r.size.height = height; [w setFrame:[w frameRectForContentRect:r] display:YES]; } } else { MoveResizeWindow(macWin); } } /* *---------------------------------------------------------------------- * * XMoveResizeWindow -- * | > > > | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | XResizeWindow( Display *display, /* Display. */ Window window, /* Window. */ unsigned int width, unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { NSRect r = [w contentRectForFrameRect:[w frame]]; r.origin.y += r.size.height - height; r.size.width = width; r.size.height = height; [w setFrame:[w frameRectForContentRect:r] display:YES]; } } else { MoveResizeWindow(macWin); } } /* *---------------------------------------------------------------------- * * XMoveResizeWindow -- * * Move or resize a given X window. See X windows documentation for * further details. * * Results: * None. * * Side effects: * None. * |
︙ | ︙ | |||
398 399 400 401 402 403 404 405 | unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { | > | | | | | | | | | | | > | < | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { /* * We explicitly convert everything to doubles so we don't get * surprised (again) by what happens when you do arithmetic with * unsigned ints. */ CGFloat X = (CGFloat) x; CGFloat Y = (CGFloat) y; CGFloat Width = (CGFloat) width; CGFloat Height = (CGFloat) height; CGFloat XOff = (CGFloat) macWin->winPtr->wmInfoPtr->xInParent; CGFloat YOff = (CGFloat) macWin->winPtr->wmInfoPtr->yInParent; NSRect r = NSMakeRect( X + XOff, tkMacOSXZeroScreenHeight - Y - YOff - Height, Width, Height); [w setFrame:[w frameRectForContentRect:r] display:YES]; } } else { MoveResizeWindow(macWin); } } /* *---------------------------------------------------------------------- * * XMoveWindow -- * * Move a given X window. See X windows documentation for further details. * * Results: * None. * * Side effects: * None. * |
︙ | ︙ | |||
449 450 451 452 453 454 455 456 | int x, int y) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { | > | > | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | int x, int y) { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; if (w) { [w setFrameTopLeftPoint: NSMakePoint( x, tkMacOSXZeroScreenHeight - y)]; } } else { MoveResizeWindow(macWin); } } /* |
︙ | ︙ | |||
491 492 493 494 495 496 497 | if (Tk_IsEmbedded(macWin->winPtr)) { TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr); if (contWinPtr) { macParent = contWinPtr->privatePtr; } else { | < < | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | if (Tk_IsEmbedded(macWin->winPtr)) { TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr); if (contWinPtr) { macParent = contWinPtr->privatePtr; } else { /* * Here we should handle out of process embedding. At this point, * we are assuming that the changes.x,y is not maintained, if you * need the info get it from Tk_GetRootCoords, and that the * toplevel sits at 0,0 when it is drawn. */ } } else { /* * TODO: update all xOff & yOffs */ macParent = macWin->winPtr->parentPtr->privatePtr; parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; } |
︙ | ︙ | |||
592 593 594 595 596 597 598 | { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { TkWmRestackToplevel(macWin->winPtr, Above, NULL); } else { | < | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { TkWmRestackToplevel(macWin->winPtr, Above, NULL); } else { /* * TODO: this should generate damage */ } } #if 0 |
︙ | ︙ | |||
627 628 629 630 631 632 633 | { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { TkWmRestackToplevel(macWin->winPtr, Below, NULL); } else { | < | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | { MacDrawable *macWin = (MacDrawable *) window; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { TkWmRestackToplevel(macWin->winPtr, Below, NULL); } else { /* * TODO: this should generate damage */ } } #endif |
︙ | ︙ | |||
690 691 692 693 694 695 696 | Rect bounds; NSRect r; if (view) { TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); TkMacOSXWinBounds(winPtr, &bounds); r = NSMakeRect(bounds.left, | | | > | | > | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | Rect bounds; NSRect r; if (view) { TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); TkMacOSXWinBounds(winPtr, &bounds); r = NSMakeRect(bounds.left, [view bounds].size.height - bounds.bottom, bounds.right - bounds.left, bounds.bottom - bounds.top); [view setNeedsDisplayInRect:r]; } } #if 0 TkGenWMMoveRequestEvent(macWin->winPtr, macWin->winPtr->changes.x, macWin->winPtr->changes.y); #endif } /* *---------------------------------------------------------------------- * * TkMacOSXSetDrawingEnabled -- * |
︙ | ︙ | |||
719 720 721 722 723 724 725 | * The clipping regions for the window and its children are cleared. * *---------------------------------------------------------------------- */ void TkMacOSXSetDrawingEnabled( | | | | | | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | * The clipping regions for the window and its children are cleared. * *---------------------------------------------------------------------- */ void TkMacOSXSetDrawingEnabled( TkWindow *winPtr, int flag) { TkWindow *childPtr; MacDrawable *macWin = winPtr->privatePtr; if (macWin) { if (flag) { macWin->flags &= ~TK_DO_NOT_DRAW; } else { macWin->flags |= TK_DO_NOT_DRAW; } } /* * Set the flag for all children & their descendants, excluding Toplevels. * (??? Do we need to exclude Toplevels?) */ childPtr = winPtr->childList; while (childPtr) { if (!Tk_IsTopLevel(childPtr)) { TkMacOSXSetDrawingEnabled(childPtr, flag); } |
︙ | ︙ | |||
899 900 901 902 903 904 905 | if (!HIShapeIsEmpty(diffRgn)) { macWin->visRgn = HIShapeCreateCopy(rgn); } CFRelease(diffRgn); } CFRelease(rgn); } else { | < | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | if (!HIShapeIsEmpty(diffRgn)) { macWin->visRgn = HIShapeCreateCopy(rgn); } CFRelease(diffRgn); } CFRelease(rgn); } else { /* * An unmapped window has empty clip regions to prevent any * (erroneous) drawing into it or its children from becoming * visible. [Bug 940117] */ if (!Tk_IsTopLevel(winPtr)) { |
︙ | ︙ | |||
929 930 931 932 933 934 935 | /* *---------------------------------------------------------------------- * * TkMacOSXVisableClipRgn -- * * This function returns the Macintosh clipping region for the given | | | | | > > > > > | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | /* *---------------------------------------------------------------------- * * TkMacOSXVisableClipRgn -- * * This function returns the Macintosh clipping region for the given * window. The caller is responsible for disposing of the returned region * via TkDestroyRegion(). * * Results: * The region. * * Side effects: * None. * *---------------------------------------------------------------------- */ TkRegion TkMacOSXVisableClipRgn( TkWindow *winPtr) { if (winPtr->privatePtr->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(winPtr); } return (TkRegion) HIShapeCreateMutableCopy(winPtr->privatePtr->visRgn); } /* *---------------------------------------------------------------------- * * TkMacOSXInvalidateViewRegion -- * * This function invalidates the given region of a view. * * Results: * None. * * Side effects: * Damage is created. * *---------------------------------------------------------------------- */ static OSStatus InvalViewRect( int msg, HIShapeRef rgn, const CGRect *rect, void *ref) { static CGAffineTransform t; NSView *view = ref; if (!view) { return paramErr; } switch (msg) { |
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | > | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | * * Side effects: * None. * *---------------------------------------------------------------------- */ NSWindow * TkMacOSXDrawableWindow( Drawable drawable) { MacDrawable *macWin = (MacDrawable *) drawable; NSWindow *result = nil; if (!macWin || macWin->flags & TK_IS_PIXMAP) { result = nil; } else if (macWin->toplevel && macWin->toplevel->winPtr && macWin->toplevel->winPtr->wmInfoPtr && macWin->toplevel->winPtr->wmInfoPtr->window) { result = macWin->toplevel->winPtr->wmInfoPtr->window; } else if (macWin->winPtr && macWin->winPtr->wmInfoPtr && macWin->winPtr->wmInfoPtr->window) { result = macWin->winPtr->wmInfoPtr->window; } else if (macWin->toplevel && (macWin->toplevel->flags & TK_EMBEDDED)) { TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); if (contWinPtr) { result = TkMacOSXDrawableWindow((Drawable) contWinPtr->privatePtr); } } return result; } |
︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | > | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | * * Side effects: * None. * *---------------------------------------------------------------------- */ NSView * TkMacOSXDrawableView( MacDrawable *macWin) { NSView *result = nil; if (!macWin) { result = nil; } else if (!macWin->toplevel) { result = macWin->view; } else if (!(macWin->toplevel->flags & TK_EMBEDDED)) { result = macWin->toplevel->view; } else { TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); if (contWinPtr) { result = TkMacOSXDrawableView(contWinPtr->privatePtr); } } return result; } |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | *---------------------------------------------------------------------- */ void * TkMacOSXGetRootControl( Drawable drawable) { | < | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 | *---------------------------------------------------------------------- */ void * TkMacOSXGetRootControl( Drawable drawable) { /* * will probably need to fix this up for embedding */ return TkMacOSXDrawableView((MacDrawable *) drawable); } |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 | */ void TkMacOSXWinBounds( TkWindow *winPtr, void *bounds) { | | > | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | */ void TkMacOSXWinBounds( TkWindow *winPtr, void *bounds) { Rect *b = (Rect *) bounds; b->left = winPtr->privatePtr->xOff; b->top = winPtr->privatePtr->yOff; b->right = b->left + winPtr->changes.width; b->bottom = b->top + winPtr->changes.height; } /* |
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 | TkWindow *winPtr, int deltaX, int deltaY) { TkWindow *childPtr; if (winPtr->privatePtr == NULL) { | < | 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 | TkWindow *winPtr, int deltaX, int deltaY) { TkWindow *childPtr; if (winPtr->privatePtr == NULL) { /* * We haven't called Tk_MakeWindowExist for this window yet. The offset * information will be postponed and calulated at that time. (This will * usually only happen when a mapped parent is being moved but has * child windows that have yet to be mapped.) */ |
︙ | ︙ |
Changes to macosx/tkMacOSXTest.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 | #include "tkMacOSXPrivate.h" /* * Forward declarations of procedures defined later in this file: */ static int DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp, | > | > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include "tkMacOSXPrivate.h" /* * Forward declarations of procedures defined later in this file: */ #if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 static int DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #endif /* *---------------------------------------------------------------------- * * TkplatformtestInit -- * * Defines commands that test platform specific functionality for |
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | TkplatformtestInit( Tcl_Interp *interp) /* Interpreter to add commands to. */ { /* * Add commands for platform specific tests on MacOS here. */ Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * DebuggerObjCmd -- * | > > | > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | TkplatformtestInit( Tcl_Interp *interp) /* Interpreter to add commands to. */ { /* * Add commands for platform specific tests on MacOS here. */ #if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * DebuggerObjCmd -- * * This procedure simply calls the low level debugger, which was * deprecated in OSX 10.8. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 static int DebuggerObjCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Not used. */ int objc, /* Not used. */ Tcl_Obj *const objv[]) /* Not used. */ { Debugger(); return TCL_OK; } #endif /* *---------------------------------------------------------------------- * * TkTestAppIsDrawing -- * * A test widget display procedure which records calls can use this to |
︙ | ︙ |
Changes to macosx/tkMacOSXWindowEvent.c.
︙ | ︙ | |||
64 65 66 67 68 69 70 | - (void) windowBoundsChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif BOOL movedOnly = [[notification name] | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | - (void) windowBoundsChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif BOOL movedOnly = [[notification name] isEqualToString:NSWindowDidMoveNotification]; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; int x, y, width = -1, height = -1, flags = 0; |
︙ | ︙ | |||
87 88 89 90 91 92 93 | if (!movedOnly && (winPtr->changes.width != bounds.size.width || winPtr->changes.height != bounds.size.height)) { width = bounds.size.width - wmPtr->xInParent; height = bounds.size.height - wmPtr->yInParent; flags |= TK_SIZE_CHANGED; } if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) { | < | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | if (!movedOnly && (winPtr->changes.width != bounds.size.width || winPtr->changes.height != bounds.size.height)) { width = bounds.size.width - wmPtr->xInParent; height = bounds.size.height - wmPtr->yInParent; flags |= TK_SIZE_CHANGED; } if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) { /* * Propagate geometry changes immediately. */ flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY; } |
︙ | ︙ | |||
136 137 138 139 140 141 142 | } } } - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame { | < | | | < | | | < > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | } } } - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame { /* * This method needs to be implemented in order for [NSWindow isZoomed] to * give the correct answer. But it suffices to always validate every * request. */ return newFrame; } - (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize { /* * We don't need to change the proposed size, but we do need to implement * this method. Otherwise the full screen window will be sized to the * screen's visibleFrame, leaving black bands at the top and bottom. */ return proposedSize; } - (void) windowEnteredFullScreen: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); |
︙ | ︙ | |||
204 205 206 207 208 209 210 | if (_windowWithMouse == w) { _windowWithMouse = nil; [w release]; } } /* | | | < | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | if (_windowWithMouse == w) { _windowWithMouse = nil; [w release]; } } /* * If necessary, TkGenWMDestroyEvent() handles [close]ing the window, so * can always return NO from -windowShouldClose: for a Tk window. */ return (winPtr ? NO : YES); } #ifdef TK_MAC_DEBUG_NOTIFICATIONS - (void) windowDragStart: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); } |
︙ | ︙ | |||
251 252 253 254 255 256 257 | NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { //Tk_UnmapWindow((Tk_Window) winPtr); } } | < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { //Tk_UnmapWindow((Tk_Window) winPtr); } } #endif /* TK_MAC_DEBUG_NOTIFICATIONS */ - (void) _setupWindowNotifications { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; |
︙ | ︙ | |||
359 360 361 362 363 364 365 | #pragma mark - /* *---------------------------------------------------------------------- * * TkpAppIsDrawing -- * | | | | | | > < | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | #pragma mark - /* *---------------------------------------------------------------------- * * TkpAppIsDrawing -- * * A widget display procedure can call this to determine whether it is * being run inside of the drawRect method. This is needed for some tests, * especially of the Text widget, which record data in a global Tcl * variable and assume that display procedures will be run in a * predictable sequence as Tcl idle tasks. * * Results: * True only while running the drawRect method of a TKContentView; * * Side effects: * None * *---------------------------------------------------------------------- */ MODULE_SCOPE Bool TkpAppIsDrawing(void) { return [NSApp isDrawing]; } /* *---------------------------------------------------------------------- * * GenerateUpdates -- * * Given a Macintosh update region and a Tk window this function geneates |
︙ | ︙ | |||
666 667 668 669 670 671 672 | if (flags & TK_LOCATION_CHANGED) { wmPtr->x = x; wmPtr->y = y; } if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) && ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) { if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) { | < < < < < | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | if (flags & TK_LOCATION_CHANGED) { wmPtr->x = x; wmPtr->y = y; } if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) && ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) { if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) { /* * Don't set external width, since the user didn't change it * from what the widgets asked for. */ } else if (wmPtr->gridWin != NULL) { wmPtr->width = wmPtr->reqGridWidth + (width - winPtr->reqWidth)/wmPtr->widthInc; if (wmPtr->width < 0) { wmPtr->width = 0; } } else { wmPtr->width = width; } if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) { /* * Don't set external height, since the user didn't change it * from what the widgets asked for. */ } else if (wmPtr->gridWin != NULL) { wmPtr->height = wmPtr->reqGridHeight + (height - winPtr->reqHeight)/wmPtr->heightInc; if (wmPtr->height < 0) { wmPtr->height = 0; } } else { wmPtr->height = height; } wmPtr->configWidth = width; wmPtr->configHeight = height; } } /* * Now set up the changes structure. Under X we wait for the * ConfigureNotify to set these values. On the Mac we know imediatly that * this is what we want - so we just set them. However, we need to make * sure the windows clipping region is marked invalid so the change is * visible to the subwindow. |
︙ | ︙ | |||
862 863 864 865 866 867 868 | * Widgets it was necessary to use Apple private API calls. In order to avoid * using private API calls, the NSView-based widgets have been replaced with * normal Tk widgets which draw themselves as native widgets by using the * HITheme API. * */ | > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | * Widgets it was necessary to use Apple private API calls. In order to avoid * using private API calls, the NSView-based widgets have been replaced with * normal Tk widgets which draw themselves as native widgets by using the * HITheme API. * */ /* * Restrict event processing to Expose events. */ static Tk_RestrictAction ExposeRestrictProc( ClientData arg, XEvent *eventPtr) { return (eventPtr->type==Expose && eventPtr->xany.serial==PTR2UINT(arg) ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } /* * Restrict event processing to ConfigureNotify events. */ static Tk_RestrictAction ConfigureRestrictProc( ClientData arg, XEvent *eventPtr) { return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } /* * If a window gets mapped inside the drawRect method, this will be run as an * idle task, after drawRect returns, to clean up the mess. */ static void RedisplayView( ClientData clientdata) { NSView *view = (NSView *) clientdata; /* * Make sure that we are not trying to displaying a view that no longer * exists. */ for (NSWindow *w in [NSApp orderedWindows]) { if ([w contentView] == view) { [view setNeedsDisplay:YES]; break; } } } @implementation TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect { const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; #ifdef TK_MAC_DEBUG_DRAWING TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); if (winPtr) fprintf(stderr, "drawRect: drawing %s\n", Tk_PathName(winPtr)); #endif /* * We do not allow recursive calls to drawRect, but we only log them on OSX * > 10.13, where they should never happen. */ if ([NSApp isDrawing]) { if ([NSApp macMinorVersion] > 13) { TKLog(@"WARNING: a recursive call to drawRect was aborted."); } return; |
︙ | ︙ | |||
926 927 928 929 930 931 932 933 934 935 936 937 938 939 | r.origin.y = height - (r.origin.y + r.size.height); HIShapeUnionWithRect(drawShape, &r); } [self generateExposeEvents:(HIShapeRef)drawShape]; CFRelease(drawShape); [NSApp setIsDrawing: NO]; #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); #endif } -(void) setFrameSize: (NSSize)newsize | > > > > > | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | r.origin.y = height - (r.origin.y + r.size.height); HIShapeUnionWithRect(drawShape, &r); } [self generateExposeEvents:(HIShapeRef)drawShape]; CFRelease(drawShape); [NSApp setIsDrawing: NO]; if ([self needsRedisplay]) { [self setNeedsRedisplay:NO]; Tcl_DoWhenIdle(RedisplayView, self); } #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); #endif } -(void) setFrameSize: (NSSize)newsize |
︙ | ︙ | |||
951 952 953 954 955 956 957 | if (winPtr) { unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; ClientData oldArg; Tk_RestrictProc *oldProc; /* | | | | | | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | if (winPtr) { unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; ClientData oldArg; Tk_RestrictProc *oldProc; /* * This can be called from outside the Tk event loop. Since it calls * Tcl_DoOneEvent, we need to make sure we don't clobber the * AutoreleasePool set up by the caller. */ [NSApp _lockAutoreleasePool]; /* * Disable Tk drawing until the window has been completely configured. */ TkMacOSXSetDrawingEnabled(winPtr, 0); /* * Generate and handle a ConfigureNotify event for the new size. */ TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg); Tk_RestrictEvents(oldProc, oldArg, &oldArg); /* * Now that Tk has configured all subwindows, create the clip regions. */ |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | * were created when the expose events were processed. */ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } /* | | | | < | | < < | < | < < > | | | 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 | * were created when the expose events were processed. */ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} } } /* * This method is called when a user changes between light and dark mode. The * implementation here generates a Tk virtual event which can be bound to a * function that redraws the window in an appropriate style. */ - (void) viewDidChangeEffectiveAppearance { XVirtualEvent event; int x, y; NSWindow *w = [self window]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; if (!winPtr) { return; } bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); event.send_event = false; event.display = Tk_Display(tkwin); event.event = Tk_WindowId(tkwin); event.root = XRootWindow(Tk_Display(tkwin), 0); event.subwindow = None; event.time = TkpGetMS(); XQueryPointer(NULL, winPtr->window, NULL, NULL, &event.x_root, &event.y_root, &x, &y, &event.state); Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y); event.same_screen = true; if (TkMacOSXInDarkMode(tkwin)) { event.name = Tk_GetUid("DarkAqua"); } else { event.name = Tk_GetUid("LightAqua"); } Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); } /* * This is no-op on 10.7 and up because Apple has removed this widget, but we * are leaving it here for backwards compatibility. */ - (void) tkToolbarButton: (id) sender { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd); #endif |
︙ | ︙ |
Changes to macosx/tkMacOSXWm.c.
1 2 3 4 5 | /* * tkMacOSXWm.c -- * * This module takes care of the interactions between a Tk-based * application and the window manager. Among other things, it implements | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tkMacOSXWm.c -- * * This module takes care of the interactions between a Tk-based * application and the window manager. Among other things, it implements * the "wm" command and passes geometry information to the window manager. * * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright (c) 2010 Kevin Walzer/WordTech Communications LLC. * Copyright (c) 2017-2019 Marc Culler. * |
︙ | ︙ | |||
388 389 390 391 392 393 394 | /* * This avoids including the title bar for full screen windows * but does include it for normal windows. */ if ([self styleMask] & NSFullScreenWindowMask) { frameRect = [NSWindow frameRectForContentRect:NSZeroRect | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | /* * This avoids including the title bar for full screen windows * but does include it for normal windows. */ if ([self styleMask] & NSFullScreenWindowMask) { frameRect = [NSWindow frameRectForContentRect:NSZeroRect styleMask:[self styleMask]]; } else { frameRect = [self frameRectForContentRect:NSZeroRect]; } WmInfo *wmPtr = winPtr->wmInfoPtr; wmPtr->xInParent = -frameRect.origin.x; |
︙ | ︙ | |||
450 451 452 453 454 455 456 | - (id) retain { id result = [super retain]; const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } | | | | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | - (id) retain { id result = [super retain]; const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } if (DEBUG_ZOMBIES > 1) { fprintf(stderr, "Retained <%s>. Count is: %lu\n", title, [self retainCount]); } return result; } - (id) autorelease { id result = [super autorelease]; const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } if (DEBUG_ZOMBIES > 1) { fprintf(stderr, "Autoreleased <%s>. Count is %lu\n", title, [self retainCount]); } return result; } - (oneway void) release { const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } if (DEBUG_ZOMBIES > 1) { fprintf(stderr, "Releasing <%s>. Count is %lu\n", title, [self retainCount]); } [super release]; } - (void) dealloc { const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } if (DEBUG_ZOMBIES > 0) { fprintf(stderr, ">>>> Freeing <%s>. Count is %lu\n", title, [self retainCount]); } [super dealloc]; } #endif |
︙ | ︙ | |||
994 995 996 997 998 999 1000 | /* Activate the highest window left on the screen. */ NSArray *windows = [NSApp orderedWindows]; for (id nswindow in windows) { TkWindow *winPtr2 = TkMacOSXGetTkWindow(nswindow); if (winPtr2 && nswindow != window) { WmInfo *wmPtr = winPtr2->wmInfoPtr; | | | > > > > < | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | /* Activate the highest window left on the screen. */ NSArray *windows = [NSApp orderedWindows]; for (id nswindow in windows) { TkWindow *winPtr2 = TkMacOSXGetTkWindow(nswindow); if (winPtr2 && nswindow != window) { WmInfo *wmPtr = winPtr2->wmInfoPtr; BOOL minimized = (wmPtr->hints.initial_state == IconicState || wmPtr->hints.initial_state == WithdrawnState); /* * If no windows are left on the screen and the next window is * iconified or withdrawn, we don't want to make it be the * KeyWindow because that would cause it to be displayed on the * screen. */ if ([nswindow canBecomeKeyWindow] && !minimized) { [nswindow makeKeyAndOrderFront:NSApp]; break; } } } /* * Process all window events immediately to force the closed window to * be deallocated. But don't do this for the root window as that is * unnecessary and can lead to segfaults. */ if (winPtr->parentPtr) { while (Tk_DoOneEvent(TK_WINDOW_EVENTS|TK_DONT_WAIT)) {} } [NSApp _resetAutoreleasePool]; #if DEBUG_ZOMBIES > 0 fprintf(stderr, "================= Pool dump ===================\n"); [NSAutoreleasePool showPools]; #endif } ckfree(wmPtr); winPtr->wmInfoPtr = NULL; |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 | } if (objc == 3) { if (wmPtr->commandObj != NULL) { Tcl_SetObjResult(interp, wmPtr->commandObj); } return TCL_OK; } | | | 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 | } if (objc == 3) { if (wmPtr->commandObj != NULL) { Tcl_SetObjResult(interp, wmPtr->commandObj); } return TCL_OK; } if (*Tcl_GetString(objv[3]) == '\0') { if (wmPtr->commandObj != NULL) { Tcl_DecrRefCount(wmPtr->commandObj); wmPtr->commandObj = NULL; } return TCL_OK; } if (Tcl_ListObjLength(interp, objv[3], &len) != TCL_OK) { |
︙ | ︙ | |||
2621 2622 2623 2624 2625 2626 2627 | return TCL_OK; } if (*Tcl_GetString(objv[3]) == '\0') { wmPtr->hints.flags &= ~IconPositionHint; } else { if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) | | | 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 | return TCL_OK; } if (*Tcl_GetString(objv[3]) == '\0') { wmPtr->hints.flags &= ~IconPositionHint; } else { if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) { return TCL_ERROR; } wmPtr->hints.icon_x = x; wmPtr->hints.icon_y = y; wmPtr->hints.flags |= IconPositionHint; } return TCL_OK; |
︙ | ︙ | |||
3452 3453 3454 3455 3456 3457 3458 | } if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings, sizeof(char *), "argument", 0, &index) != TCL_OK) { return TCL_ERROR; } | > | > > | > | > | > | 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 | } if (Tcl_GetIndexFromObjStruct(interp, objv[3], optionStrings, sizeof(char *), "argument", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case OPT_NORMAL: TkpWmSetState(winPtr, NormalState); /* * This varies from 'wm deiconify' because it does not force the * window to be raised and receive focus */ break; case OPT_ICONIC: if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't iconify \"%s\": override-redirect flag is set", winPtr->pathName)); Tcl_SetErrorCode(interp, "TK", "WM", "STATE", "OVERRIDE_REDIRECT", NULL); return TCL_ERROR; } if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't iconify \"%s\": it is a transient", winPtr->pathName)); Tcl_SetErrorCode(interp, "TK", "WM", "STATE", "TRANSIENT", NULL); return TCL_ERROR; } TkpWmSetState(winPtr, IconicState); break; case OPT_WITHDRAWN: TkpWmSetState(winPtr, WithdrawnState); break; default: /* OPT_ZOOMED */ TkpWmSetState(winPtr, ZoomState); break; } } else if (wmPtr->iconFor != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("icon", -1)); } else { if (wmPtr->hints.initial_state == NormalState || wmPtr->hints.initial_state == ZoomState) { wmPtr->hints.initial_state = (TkMacOSXIsWindowZoomed(winPtr) ? |
︙ | ︙ | |||
3598 3599 3600 3601 3602 3603 3604 | if (objc == 3) { if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(wmPtr->master), -1)); } return TCL_OK; } | | < < > > | > > | 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 | if (objc == 3) { if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(wmPtr->master), -1)); } return TCL_OK; } if (*Tcl_GetString(objv[3]) == '\0') { RemoveTransient(winPtr); } else { if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) { return TCL_ERROR; } masterPtr = (TkWindow*) master; while (!Tk_TopWinHierarchy(masterPtr)) { /* * Ensure that the master window is actually a Tk toplevel. */ masterPtr = masterPtr->parentPtr; } Tk_MakeWindowExist((Tk_Window)masterPtr); if (wmPtr->iconFor != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't make \"%s\" a transient: it is an icon for %s", Tcl_GetString(objv[2]), Tk_PathName(wmPtr->iconFor))); Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "ICON", NULL); return TCL_ERROR; } wmPtr2 = masterPtr->wmInfoPtr; /* * Under some circumstances, wmPtr2 is NULL here. */ if (wmPtr2 != NULL && wmPtr2->iconFor != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't make \"%s\" a master: it is an icon for %s", Tcl_GetString(objv[3]), Tk_PathName(wmPtr2->iconFor))); Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "ICON", NULL); return TCL_ERROR; } |
︙ | ︙ | |||
3676 3677 3678 3679 3680 3681 3682 | } wmPtr->master = (Tk_Window) masterPtr; } ApplyMasterOverrideChanges(winPtr, NULL); return TCL_OK; } | | | 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 | } wmPtr->master = (Tk_Window) masterPtr; } ApplyMasterOverrideChanges(winPtr, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * RemoveTransient -- * * Clears the transient's master record and removes the transient from the * master's list. |
︙ | ︙ | |||
3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 | NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); [win orderOut:nil]; [win setExcludedFromWindowsMenu:YES]; /* * If this window has a transient, the transient must also be withdrawn. */ for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; TkWindow *masterPtr = (TkWindow *) TkGetTransientMaster(winPtr2); if (masterPtr == winPtr && winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { TkpWmSetState(winPtr2, WithdrawnState); transientPtr->flags |= WITHDRAWN_BY_MASTER; } } return TCL_OK; } | > | | | | 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 | NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); [win orderOut:nil]; [win setExcludedFromWindowsMenu:YES]; /* * If this window has a transient, the transient must also be withdrawn. */ for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; TkWindow *masterPtr = (TkWindow *) TkGetTransientMaster(winPtr2); if (masterPtr == winPtr && winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { TkpWmSetState(winPtr2, WithdrawnState); transientPtr->flags |= WITHDRAWN_BY_MASTER; } } return TCL_OK; } /* * Invoked by those wm subcommands that affect geometry. Schedules a geometry * update. */ static void WmUpdateGeom( WmInfo *wmPtr, TkWindow *winPtr) { |
︙ | ︙ | |||
4414 4415 4416 4417 4418 4419 4420 4421 | */ wmPtr->width = width; wmPtr->height = height; if (flags & WM_NEGATIVE_X) { int borderwidth = wmPtr->parentWidth - winPtr->changes.width; int newWidth = width == -1 ? winPtr->changes.width : width; x = (x == -1) ? | > | | > | | | 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 | */ wmPtr->width = width; wmPtr->height = height; if (flags & WM_NEGATIVE_X) { int borderwidth = wmPtr->parentWidth - winPtr->changes.width; int newWidth = width == -1 ? winPtr->changes.width : width; x = (x == -1) ? wmPtr->x + winPtr->changes.width - newWidth : wmPtr->vRootWidth - x - newWidth - borderwidth; } if (x == -1) { x = wmPtr->x; } if (flags & WM_NEGATIVE_Y) { int borderheight = wmPtr->parentHeight - winPtr->changes.height; int newHeight = height == -1 ? winPtr->changes.height : height; y = (y == -1) ? wmPtr->y + winPtr->changes.height - newHeight : wmPtr->vRootHeight - y - newHeight - borderheight; } if (y == -1) { y = wmPtr->y; } if (wmPtr->flags & WM_FULLSCREEN) { wmPtr->configX = x; wmPtr->configY = y; |
︙ | ︙ | |||
4553 4554 4555 4556 4557 4558 4559 | * This is a Macintosh specific implementation of this function. Given * the root coordinates of a point, this procedure returns the token for * the top-most window covering that point, if there exists such a window * in this application. * * Results: * The return result is either a token for the window corresponding to | | < | 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 | * This is a Macintosh specific implementation of this function. Given * the root coordinates of a point, this procedure returns the token for * the top-most window covering that point, if there exists such a window * in this application. * * Results: * The return result is either a token for the window corresponding to * rootX and rootY, or else NULL to indicate that there is no such window. * * Side effects: * None. * *---------------------------------------------------------------------- */ |
︙ | ︙ | |||
5516 5517 5518 5519 5520 5521 5522 | TkUnsupported1ObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { static const char *const subcmds[] = { | | | | 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 | TkUnsupported1ObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { static const char *const subcmds[] = { "style", "tabbingid", "appearance", "isdark", NULL }; enum SubCmds { TKMWS_STYLE, TKMWS_TABID, TKMWS_APPEARANCE, TKMWS_ISDARK }; Tk_Window tkwin = clientData; TkWindow *winPtr; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?"); |
︙ | ︙ | |||
5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 | Tcl_SetObjResult(interp, Tcl_NewStringObj( "Window appearances cannot be changed before OSX 10.14.", -1)); Tcl_SetErrorCode(interp, "TK", "WINDOWSTYLE", "APPEARANCE", NULL); return TCL_ERROR; } return WmWinAppearance(interp, winPtr, objc, objv); default: return TCL_ERROR; } } /* *---------------------------------------------------------------------- | > > > > > > > | 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 | Tcl_SetObjResult(interp, Tcl_NewStringObj( "Window appearances cannot be changed before OSX 10.14.", -1)); Tcl_SetErrorCode(interp, "TK", "WINDOWSTYLE", "APPEARANCE", NULL); return TCL_ERROR; } return WmWinAppearance(interp, winPtr, objc, objv); case TKMWS_ISDARK: if ((objc != 3)) { Tcl_WrongNumArgs(interp, 2, objv, "isdark window"); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(TkMacOSXInDarkMode(tkwin))); return TCL_OK; default: return TCL_ERROR; } } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
5896 5897 5898 5899 5900 5901 5902 | APPEARANCE_AQUA, APPEARANCE_DARKAQUA, APPEARANCE_AUTO }; Tcl_Obj *result = NULL; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 NSAppearanceName appearance; #else NSString *appearance; | | | < > | | < < < | < < | > < | > > | | > > < | > | 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 | APPEARANCE_AQUA, APPEARANCE_DARKAQUA, APPEARANCE_AUTO }; Tcl_Obj *result = NULL; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 NSAppearanceName appearance; #else NSString *appearance; #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 const char *resultString = "unrecognized"; NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); if (win) { appearance = win.appearance.name; if (appearance == nil) { resultString = appearanceStrings[APPEARANCE_AUTO]; } else if (appearance == NSAppearanceNameAqua) { resultString = appearanceStrings[APPEARANCE_AQUA]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 } else if (@available(macOS 10.14, *)) { if (appearance == NSAppearanceNameDarkAqua) { resultString = appearanceStrings[APPEARANCE_DARKAQUA]; } #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 } result = Tcl_NewStringObj(resultString, strlen(resultString)); } if (result == NULL) { Tcl_Panic("Failed to read appearance name."); } if (objc == 4) { int index; if (Tcl_GetIndexFromObjStruct(interp, objv[3], appearanceStrings, sizeof(char *), "appearancename", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum appearances) index) { case APPEARANCE_AQUA: win.appearance = [NSAppearance appearanceNamed: NSAppearanceNameAqua]; break; case APPEARANCE_DARKAQUA: #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 if (@available(macOS 10.14, *)) { win.appearance = [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua]; } #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 break; default: win.appearance = nil; } } Tcl_SetObjResult(interp, result); return TCL_OK; #else // MAC_OS_X_VERSION_MAX_ALLOWED > 1090 return TCL_ERROR; #endif } /* *---------------------------------------------------------------------- * * TkpMakeMenuWindow -- * |
︙ | ︙ | |||
6136 6137 6138 6139 6140 6141 6142 | } /* *---------------------------------------------------------------------- * * TkpDisplayWindow -- * | | | | | | | | 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 | } /* *---------------------------------------------------------------------- * * TkpDisplayWindow -- * * Mark the contentView of this window as needing display so the window * will be drawn by the window manager. If this is called within the * drawRect method, do nothing. * * Results: * None. * * Side effects: * The window's contentView is marked as needing display. * *---------------------------------------------------------------------- */ MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin) { if (![NSApp isDrawing]) { TkWindow *winPtr = (TkWindow *) tkwin; NSWindow *w = TkMacOSXDrawableWindow(winPtr->window); [[w contentView] setNeedsDisplay: YES]; } } /* *---------------------------------------------------------------------- * * TkMacOSXRegisterOffScreenWindow -- * * This function adds the passed in Off Screen Port to the hash table that * maps Mac windows to root X windows. * * Results: * None. * * Side effects: * An entry is added to the windowTable hash table. * |
︙ | ︙ | |||
6973 6974 6975 6976 6977 6978 6979 | NSResizableWindowMask; } else { styleMask |= NSTitledWindowMask; } } if (macWindow) { structureRect = [NSWindow frameRectForContentRect:NSZeroRect | | | 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 | NSResizableWindowMask; } else { styleMask |= NSTitledWindowMask; } } if (macWindow) { structureRect = [NSWindow frameRectForContentRect:NSZeroRect styleMask:styleMask]; /* * Synchronize the wmInfoPtr to match the new window configuration * so windowBoundsChanged won't corrupt the window manager info. */ wmPtr->xInParent = -structureRect.origin.x; |
︙ | ︙ | |||
7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 | static void RemapWindows( TkWindow *winPtr, MacDrawable *parentWin) { TkWindow *childPtr; /* * Remove the OS specific window. It will get rebuilt when the window gets * Mapped. */ if (winPtr->window != None) { MacDrawable *macWin = (MacDrawable *) winPtr->window; | > | 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 | static void RemapWindows( TkWindow *winPtr, MacDrawable *parentWin) { TkWindow *childPtr; /* * Remove the OS specific window. It will get rebuilt when the window gets * Mapped. */ if (winPtr->window != None) { MacDrawable *macWin = (MacDrawable *) winPtr->window; |
︙ | ︙ |
Changes to macosx/tkMacOSXXStubs.c.
︙ | ︙ | |||
174 175 176 177 178 179 180 | snprintf(vendor, sizeof(vendor), "Apple AppKit %g", NSAppKitVersionNumber); } display->vendor = vendor; { int major, minor, patch; | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | snprintf(vendor, sizeof(vendor), "Apple AppKit %g", NSAppKitVersionNumber); } display->vendor = vendor; { int major, minor, patch; #if MAC_OS_X_VERSION_MAX_ALLOWED < 101000 Gestalt(gestaltSystemVersionMajor, (SInt32*)&major); Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor); Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch); #else NSOperatingSystemVersion systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; major = systemVersion.majorVersion; minor = systemVersion.minorVersion; |
︙ | ︙ |
Changes to macosx/ttkMacOSXTheme.c.
1 2 3 | /* * ttkMacOSXTheme.c -- * | | | | | | | | | | > > | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | | | > | | | | | > | | | | | < > | | | | | | | | > | | < > > | | > > | | | | | | > | | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | > > | > > | > > | > > | | | | | | | | | | | < < < | | | | < | < | > > < < < < < < < < < < < < < < < < < < < | | | | > > < < < > | > > | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | /* * ttkMacOSXTheme.c -- * * Tk theme engine for Mac OSX, using the Appearance Manager API. * * Copyright (c) 2004 Joe English * Copyright (c) 2005 Neil Madden * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]> * Copyright 2008-2009, Apple Inc. * Copyright 2009 Kevin Walzer/WordTech Communications LLC. * Copyright 2019 Marc Culler * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * See also: * * <URL: http://developer.apple.com/documentation/Carbon/Reference/ * Appearance_Manager/appearance_manager/APIIndex.html > * * Notes: * "Active" means different things in Mac and Tk terminology -- * On Aqua, widgets are "Active" if they belong to the foreground window, * "Inactive" if they are in a background window. Tk uses the term * "active" to mean that the mouse cursor is over a widget; aka "hover", * "prelight", or "hot-tracked". Aqua doesn't use this kind of feedback. * * The QuickDraw/Carbon coordinate system is relative to the top-level * window, not to the Tk_Window. BoxToRect() accounts for this. */ #include "tkMacOSXPrivate.h" #include "ttk/ttkTheme.h" #include <math.h> /* * Macros for handling drawing contexts. */ #define BEGIN_DRAWING(d) { \ TkMacOSXDrawingContext dc; \ if (!TkMacOSXSetupDrawingContext((d), NULL, 1, &dc)) {return;} #define END_DRAWING \ TkMacOSXRestoreDrawingContext(&dc);} #define HIOrientation kHIThemeOrientationNormal #define NoThemeMetric 0xFFFFFFFF #ifdef __LP64__ #define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum)) #else #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ #define TTK_STATE_FIRST_TAB TTK_STATE_USER1 #define TTK_STATE_LAST_TAB TTK_STATE_USER2 #define TTK_TREEVIEW_STATE_SORTARROW TTK_STATE_USER1 /* * Colors and gradients used in Dark Mode. */ static CGFloat darkButtonFace[4] = { 112.0 / 255, 113.0 / 255, 115.0 / 255, 1.0 }; static CGFloat darkPressedBevelFace[4] = { 135.0 / 255, 136.0 / 255, 138.0 / 255, 1.0 }; static CGFloat darkSelectedBevelFace[4] = { 162.0 / 255, 163.0 / 255, 165.0 / 255, 1.0 }; static CGFloat darkDisabledButtonFace[4] = { 86.0 / 255, 87.0 / 255, 89.0 / 255, 1.0 }; static CGFloat darkInactiveSelectedTab[4] = { 159.0 / 255, 160.0 / 255, 161.0 / 255, 1.0 }; static CGFloat darkTabSeparator[4] = {0.0, 0.0, 0.0, 0.25}; static CGFloat darkTrack[4] = {1.0, 1.0, 1.0, 0.25}; static CGFloat darkFrameTop[4] = {1.0, 1.0, 1.0, 0.0625}; static CGFloat darkFrameBottom[4] = {1.0, 1.0, 1.0, 0.125}; static CGFloat darkFrameAccent[4] = {0.0, 0.0, 0.0, 0.0625}; static CGFloat darkTopGradient[8] = { 1.0, 1.0, 1.0, 0.3, 1.0, 1.0, 1.0, 0.0 }; static CGFloat darkBackgroundGradient[8] = { 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.25 }; static CGFloat darkInactiveGradient[8] = { 89.0 / 255, 90.0 / 255, 93.0 / 255, 1.0, 119.0 / 255, 120.0 / 255, 122.0 / 255, 1.0 }; static CGFloat darkSelectedGradient[8] = { 23.0 / 255, 111.0 / 255, 232.0 / 255, 1.0, 20.0 / 255, 94.0 / 255, 206.0 / 255, 1.0 }; /* * When building on systems earlier than 10.8 there is no reasonable way to * convert an NSColor to a CGColor. We do run-time checking of the OS version, * and never need the CGColor property on older systems, so we can use this * CGCOLOR macro, which evaluates to NULL without raising compiler warnings. * Similarly, we never draw rounded rectangles on older systems which did not * have CGPathCreateWithRoundedRect, so we just redefine it to return NULL. */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 #define CGCOLOR(nscolor) nscolor.CGColor #else #define CGCOLOR(nscolor) (0 ? (CGColorRef) nscolor : NULL) #define CGPathCreateWithRoundedRect(w, x, y, z) NULL #endif /*---------------------------------------------------------------------- * +++ Utilities. */ /* * BoxToRect -- * Convert a Ttk_Box in Tk coordinates relative to the given Drawable * to a native Rect relative to the containing port. */ static inline CGRect BoxToRect( Drawable d, Ttk_Box b) { MacDrawable *md = (MacDrawable *) d; CGRect rect; rect.origin.y = b.y + md->yOff; rect.origin.x = b.x + md->xOff; rect.size.height = b.height; rect.size.width = b.width; return rect; } /* * Table mapping Tk states to Appearance manager ThemeStates */ static Ttk_StateTable ThemeStateTable[] = { {kThemeStateUnavailable, TTK_STATE_DISABLED, 0}, {kThemeStatePressed, TTK_STATE_PRESSED, 0}, {kThemeStateInactive, TTK_STATE_BACKGROUND, 0}, {kThemeStateActive, 0, 0} /* Others: Not sure what these are supposed to mean. Up/Down have * something to do with "little arrow" increment controls... Dunno what * a "Rollover" is. * NEM: Rollover is TTK_STATE_ACTIVE... but we don't handle that yet, by * the looks of things * * {kThemeStateRollover, 0, 0}, * {kThemeStateUnavailableInactive, 0, 0} * {kThemeStatePressedUp, 0, 0}, * {kThemeStatePressedDown, 0, 0} */ }; /*---------------------------------------------------------------------- * NormalizeButtonBounds -- * * Apple's Human Interface Guidelines only allow three specific heights * for most buttons: Regular, small and mini. We always use the regular * size. However, Ttk may provide an arbitrary bounding rectangle. We * always draw the button centered vertically on the rectangle, and * having the same width as the rectangle. This function returns the * actual bounding rectangle that will be used in drawing the button. * * The BevelButton is allowed to have arbitrary size, and also has * external padding. This is handled separately here. */ static CGRect NormalizeButtonBounds( SInt32 heightMetric, CGRect bounds) { SInt32 height; if (heightMetric != (SInt32) NoThemeMetric) { ChkErr(GetThemeMetric, heightMetric, &height); bounds.origin.y += (bounds.size.height - height) / 2; bounds.size.height = height; } return bounds; } /*---------------------------------------------------------------------- * +++ Backgrounds * * Support for contrasting background colors when GroupBoxes or Tabbed * panes are nested inside each other. Early versions of macOS used ridged * borders, so do not need contrasting backgrounds. */ /* * For systems older than 10.14, [NSColor windowBackGroundColor] generates * garbage when called from this function. In 10.14 it works correctly, and * must be used in order to have a background color which responds to Dark * Mode. So we use this hard-wired RGBA color on the older systems which don't * support Dark Mode anyway. */ static CGFloat windowBackground[4] = { 235.0 / 255, 235.0 / 255, 235.0 / 255, 1.0 }; static CGFloat whiteRGBA[4] = {1.0, 1.0, 1.0, 1.0}; static CGFloat blackRGBA[4] = {0.0, 0.0, 0.0, 1.0}; /*---------------------------------------------------------------------- * GetBackgroundColor -- * * Fills the array rgba with the color coordinates for a background color. * Start with the background color of a window's geometry master, or the * standard ttk window background if there is no master. If the contrast * parameter is nonzero, modify this color to be darker, for the aqua * appearance, or lighter for the DarkAqua appearance. This is primarily * used by the Fill and Background elements. */ static void GetBackgroundColor( CGContextRef context, Tk_Window tkwin, int contrast, CGFloat *rgba) { TkWindow *winPtr = (TkWindow *) tkwin; TkWindow *masterPtr = (TkWindow *) TkGetGeomMaster(tkwin); while (masterPtr != NULL) { if (masterPtr->privatePtr->flags & TTK_HAS_CONTRASTING_BG) { break; } masterPtr = (TkWindow *) TkGetGeomMaster(masterPtr); } if (masterPtr) { for (int i = 0; i < 4; i++) { rgba[i] = masterPtr->privatePtr->fillRGBA[i]; } } else { if ([NSApp macMinorVersion] > 13) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *windowColor = [[NSColor windowBackgroundColor] colorUsingColorSpace: deviceRGB]; [windowColor getComponents: rgba]; } else { for (int i = 0; i < 4; i++) { rgba[i] = windowBackground[i]; } } } if (contrast) { int isDark = (rgba[0] + rgba[1] + rgba[2] < 1.5); if (isDark) { for (int i = 0; i < 3; i++) { rgba[i] += 8.0 / 255.0; } } else { for (int i = 0; i < 3; i++) { rgba[i] -= 8.0 / 255.0; } } winPtr->privatePtr->flags |= TTK_HAS_CONTRASTING_BG; for (int i = 0; i < 4; i++) { winPtr->privatePtr->fillRGBA[i] = rgba[i]; } } } /*---------------------------------------------------------------------- * +++ Single Arrow Buttons -- * * Used in ListHeaders and Comboboxes. */ static void DrawDownArrow( CGContextRef context, CGRect bounds, CGFloat inset, CGFloat size, CGFloat *rgba) { CGFloat x, y; CGContextSetRGBStrokeColor(context, rgba[0], rgba[1], rgba[2], rgba[3]); CGContextSetLineWidth(context, 1.5); x = bounds.origin.x + inset; y = bounds.origin.y + trunc(bounds.size.height / 2); CGContextBeginPath(context); CGPoint arrow[3] = { {x, y - size / 4}, {x + size / 2, y + size / 4}, {x + size, y - size / 4} }; CGContextAddLines(context, arrow, 3); CGContextStrokePath(context); } static void DrawUpArrow( CGContextRef context, CGRect bounds, CGFloat inset, CGFloat size, CGFloat *rgba) { CGFloat x, y; CGContextSetRGBStrokeColor(context, rgba[0], rgba[1], rgba[2], rgba[3]); CGContextSetLineWidth(context, 1.5); x = bounds.origin.x + inset; y = bounds.origin.y + trunc(bounds.size.height / 2); CGContextBeginPath(context); CGPoint arrow[3] = { {x, y + size / 4}, {x + size / 2, y - size / 4}, {x + size, y + size / 4} }; CGContextAddLines(context, arrow, 3); CGContextStrokePath(context); } /*---------------------------------------------------------------------- * +++ Double Arrow Buttons -- * * Used in MenuButtons and SpinButtons. */ static void DrawUpDownArrows( CGContextRef context, CGRect bounds, CGFloat inset, CGFloat size, CGFloat *rgba) { CGFloat x, y; CGContextSetRGBStrokeColor(context, rgba[0], rgba[1], rgba[2], rgba[3]); CGContextSetLineWidth(context, 1.5); x = bounds.origin.x + inset; y = bounds.origin.y + trunc(bounds.size.height / 2); CGContextBeginPath(context); CGPoint bottomArrow[3] = {{x, y + 2}, {x + size / 2, y + 2 + size / 2}, {x + size, y + 2}}; CGContextAddLines(context, bottomArrow, 3); CGPoint topArrow[3] = {{x, y - 2}, {x + size / 2, y - 2 - size / 2}, {x + size, y - 2}}; CGContextAddLines(context, topArrow, 3); CGContextStrokePath(context); } /*---------------------------------------------------------------------- * +++ FillButtonBackground -- * * Fills a rounded rectangle with a transparent black gradient. * This is a no-op if building on 10.8 or older. */ static void FillButtonBackground( CGContextRef context, CGRect bounds, CGFloat radius) { CGPathRef path; NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; CGGradientRef backgroundGradient = CGGradientCreateWithColorComponents( deviceRGB.CGColorSpace, darkBackgroundGradient, NULL, 2); CGPoint backgroundEnd = { bounds.origin.x, bounds.origin.y + bounds.size.height }; CGContextBeginPath(context); path = CGPathCreateWithRoundedRect(bounds, radius, radius, NULL); CGContextAddPath(context, path); CGContextClip(context); CGContextDrawLinearGradient(context, backgroundGradient, bounds.origin, backgroundEnd, 0); CFRelease(path); CFRelease(backgroundGradient); } /*---------------------------------------------------------------------- * +++ HighlightButtonBorder -- * * Accent the top border of a rounded rectangle with a transparent * white gradient. */ static void HighlightButtonBorder( CGContextRef context, CGRect bounds) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; CGPoint topEnd = {bounds.origin.x, bounds.origin.y + 3}; CGGradientRef topGradient = CGGradientCreateWithColorComponents( deviceRGB.CGColorSpace, darkTopGradient, NULL, 2); CGContextSaveGState(context); CGContextBeginPath(context); CGContextAddArc(context, bounds.origin.x + 4, bounds.origin.y + 4, 4, PI, 3 * PI / 2, 0); CGContextAddArc(context, bounds.origin.x + bounds.size.width - 4, bounds.origin.y + 4, 4, 3 * PI / 2, 0, 0); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextDrawLinearGradient(context, topGradient, bounds.origin, topEnd, 0.0); CGContextRestoreGState(context); CFRelease(topGradient); } /*---------------------------------------------------------------------- * DrawGroupBox -- * * This is a standalone drawing procedure which draws the contrasting * rounded rectangular box for LabelFrames and Notebook panes used in * more recent versions of macOS. */ static void DrawGroupBox( CGRect bounds, CGContextRef context, Tk_Window tkwin) { CGPathRef path; NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *borderColor, *bgColor; static CGFloat border[4] = {1.0, 1.0, 1.0, 0.25}; CGFloat fill[4]; GetBackgroundColor(context, tkwin, 1, fill); bgColor = [NSColor colorWithColorSpace: deviceRGB components: fill count: 4]; CGContextSetFillColorSpace(context, deviceRGB.CGColorSpace); CGContextSetFillColorWithColor(context, CGCOLOR(bgColor)); path = CGPathCreateWithRoundedRect(bounds, 4, 4, NULL); CGContextClipToRect(context, bounds); CGContextBeginPath(context); CGContextAddPath(context, path); CGContextFillPath(context); borderColor = [NSColor colorWithColorSpace: deviceRGB components: border count: 4]; CGContextSetFillColorWithColor(context, CGCOLOR(borderColor)); [borderColor getComponents: fill]; CGContextSetRGBFillColor(context, fill[0], fill[1], fill[2], fill[3]); CGContextBeginPath(context); CGContextAddPath(context, path); CGContextReplacePathWithStrokedPath(context); CGContextFillPath(context); CFRelease(path); } /*---------------------------------------------------------------------- * SolidFillRoundedRectangle -- * * Fill a rounded rectangle with a specified solid color. */ static void SolidFillRoundedRectangle( CGContextRef context, CGRect bounds, CGFloat radius, NSColor *color) { CGPathRef path; CGContextSetFillColorWithColor(context, CGCOLOR(color)); path = CGPathCreateWithRoundedRect(bounds, radius, radius, NULL); CGContextBeginPath(context); CGContextAddPath(context, path); CGContextFillPath(context); CFRelease(path); } /*---------------------------------------------------------------------- * +++ DrawListHeader -- * * This is a standalone drawing procedure which draws column headers for * a Treeview in the Aqua appearance. The HITheme headers have not * matched the native ones since OSX 10.8. Note that the header image is * ignored, but we draw arrows according to the state. */ static void DrawListHeader( CGRect bounds, CGContextRef context, Tk_Window tkwin, int state) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *strokeColor, *bgColor; static CGFloat borderRGBA[4] = { 200.0 / 255, 200.0 / 255, 200.0 / 255, 1.0 }; static CGFloat separatorRGBA[4] = { 220.0 / 255, 220.0 / 255, 220.0 / 255, 1.0 }; static CGFloat activeBgRGBA[4] = { 238.0 / 255, 238.0 / 255, 238.0 / 255, 1.0 }; static CGFloat inactiveBgRGBA[4] = { 246.0 / 255, 246.0 / 255, 246.0 / 255, 1.0 }; /* * Apple changes the background of a list header when the window is not * active. But Ttk does not indicate that in the state of a TreeHeader. * So we have to query the Apple window manager. */ NSWindow *win = TkMacOSXDrawableWindow(Tk_WindowId(tkwin)); CGFloat *bgRGBA = [win isKeyWindow] ? activeBgRGBA : inactiveBgRGBA; CGFloat x = bounds.origin.x, y = bounds.origin.y; CGFloat w = bounds.size.width, h = bounds.size.height; CGPoint top[2] = {{x, y + 1}, {x + w, y + 1}}; CGPoint bottom[2] = {{x, y + h}, {x + w, y + h}}; CGPoint separator[2] = {{x + w - 1, y + 3}, {x + w - 1, y + h - 3}}; bgColor = [NSColor colorWithColorSpace: deviceRGB components: bgRGBA count: 4]; CGContextSaveGState(context); CGContextSetShouldAntialias(context, false); CGContextSetFillColorSpace(context, deviceRGB.CGColorSpace); CGContextSetStrokeColorSpace(context, deviceRGB.CGColorSpace); CGContextBeginPath(context); CGContextSetFillColorWithColor(context, CGCOLOR(bgColor)); CGContextAddRect(context, bounds); CGContextFillPath(context); strokeColor = [NSColor colorWithColorSpace: deviceRGB components: separatorRGBA count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(strokeColor)); CGContextAddLines(context, separator, 2); CGContextStrokePath(context); strokeColor = [NSColor colorWithColorSpace: deviceRGB components: borderRGBA count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(strokeColor)); CGContextAddLines(context, top, 2); CGContextStrokePath(context); CGContextAddLines(context, bottom, 2); CGContextStrokePath(context); CGContextRestoreGState(context); if (state & TTK_TREEVIEW_STATE_SORTARROW) { CGRect arrowBounds = bounds; arrowBounds.origin.x = bounds.origin.x + bounds.size.width - 16; arrowBounds.size.width = 16; if (state & TTK_STATE_ALTERNATE) { DrawUpArrow(context, arrowBounds, 3, 8, blackRGBA); } else if (state & TTK_STATE_SELECTED) { DrawDownArrow(context, arrowBounds, 3, 8, blackRGBA); } } } /*---------------------------------------------------------------------- * +++ Drawing procedures for widgets in Apple's "Dark Mode" (10.14 and up). * * The HIToolbox does not support Dark Mode, and apparently never will, * so to make widgets look "native" we have to provide analogues of the * HITheme drawing functions to be used in DarkAqua. We continue to use * HITheme in Aqua, since it understands earlier versions of the OS. * * Drawing the dark widgets requires NSColors that were introduced in OSX * 10.14, so we make some of these functions be no-ops when building on * systems older than 10.14. */ /*---------------------------------------------------------------------- * GradientFillRoundedRectangle -- * * Fill a rounded rectangle with a specified gradient. */ static void GradientFillRoundedRectangle( CGContextRef context, CGRect bounds, CGFloat radius, CGFloat *colors, int numColors) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; CGPathRef path; CGPoint end = { bounds.origin.x, bounds.origin.y + bounds.size.height }; CGGradientRef gradient = CGGradientCreateWithColorComponents( deviceRGB.CGColorSpace, colors, NULL, numColors); path = CGPathCreateWithRoundedRect(bounds, radius, radius, NULL); CGContextBeginPath(context); CGContextAddPath(context, path); CGContextClip(context); CGContextDrawLinearGradient(context, gradient, bounds.origin, end, 0); CFRelease(path); CFRelease(gradient); } /*---------------------------------------------------------------------- * +++ DrawDarkButton -- * * This is a standalone drawing procedure which draws PushButtons and * PopupButtons in the Dark Mode style. */ static void DrawDarkButton( CGRect bounds, ThemeButtonKind kind, Ttk_State state, CGContextRef context) |
︙ | ︙ | |||
550 551 552 553 554 555 556 | /* * Fill the button face with the appropriate color. */ bounds = CGRectInset(bounds, 1, 1); if (kind == kThemePushButton && (state & TTK_STATE_PRESSED)) { GradientFillRoundedRectangle(context, bounds, 4, | | | | | | | | | | | | | | | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | /* * Fill the button face with the appropriate color. */ bounds = CGRectInset(bounds, 1, 1); if (kind == kThemePushButton && (state & TTK_STATE_PRESSED)) { GradientFillRoundedRectangle(context, bounds, 4, darkSelectedGradient, 2); } else { if (state & TTK_STATE_DISABLED) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkDisabledButtonFace count: 4]; } else { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkButtonFace count: 4]; } SolidFillRoundedRectangle(context, bounds, 4, faceColor); } /* * If this is a popup, draw the arrow button. */ if ((kind == kThemePopupButton) | (kind == kThemeComboBox)) { CGRect arrowBounds = bounds; arrowBounds.size.width = 16; arrowBounds.origin.x += bounds.size.width - 16; /* * If the toplevel is front, paint the button blue. */ if (!(state & TTK_STATE_BACKGROUND) && !(state & TTK_STATE_DISABLED)) { GradientFillRoundedRectangle(context, arrowBounds, 4, darkSelectedGradient, 2); } if (kind == kThemePopupButton) { DrawUpDownArrows(context, arrowBounds, 3, 7, whiteRGBA); } else { DrawDownArrow(context, arrowBounds, 4, 8, whiteRGBA); } } HighlightButtonBorder(context, bounds); } /*---------------------------------------------------------------------- * +++ DrawDarkIncDecButton -- * * This is a standalone drawing procedure which draws an IncDecButton * (as used in a Spinbox) in the Dark Mode style. */ static void DrawDarkIncDecButton( CGRect bounds, ThemeDrawState drawState, Ttk_State state, CGContextRef context) |
︙ | ︙ | |||
619 620 621 622 623 624 625 | /* * Fill the button face with the appropriate color. */ bounds = CGRectInset(bounds, 1, 1); if (state & TTK_STATE_DISABLED) { faceColor = [NSColor colorWithColorSpace: deviceRGB | | | | | | | | | | > | | | | | | | | | | | | | > | | | | | | | | | > | | | | | | | | | | > | | | | | | | | | | | | | > | | | | | | | | | | | | | > | | | | > | | | | | | | | | | | | | | > | | | | | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | /* * Fill the button face with the appropriate color. */ bounds = CGRectInset(bounds, 1, 1); if (state & TTK_STATE_DISABLED) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkDisabledButtonFace count: 4]; } else { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkButtonFace count: 4]; } SolidFillRoundedRectangle(context, bounds, 4, faceColor); /* * If pressed, paint the appropriate half blue. */ if (state & TTK_STATE_PRESSED) { CGRect clip = bounds; clip.size.height /= 2; CGContextSaveGState(context); if (drawState == kThemeStatePressedDown) { clip.origin.y += clip.size.height; } CGContextClipToRect(context, clip); GradientFillRoundedRectangle(context, bounds, 5, darkSelectedGradient, 2); CGContextRestoreGState(context); } DrawUpDownArrows(context, bounds, 3, 5, whiteRGBA); HighlightButtonBorder(context, bounds); } /*---------------------------------------------------------------------- * +++ DrawDarkBevelButton -- * * This is a standalone drawing procedure which draws RoundedBevelButtons * in the Dark Mode style. */ static void DrawDarkBevelButton( CGRect bounds, Ttk_State state, CGContextRef context) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *faceColor; CGContextClipToRect(context, bounds); FillButtonBackground(context, bounds, 5); /* * Fill the button face with the appropriate color. */ bounds = CGRectInset(bounds, 1, 1); if (state & TTK_STATE_PRESSED) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkPressedBevelFace count: 4]; } else if ((state & TTK_STATE_DISABLED) || (state & TTK_STATE_ALTERNATE)) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkDisabledButtonFace count: 4]; } else if (state & TTK_STATE_SELECTED) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkSelectedBevelFace count: 4]; } else { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkButtonFace count: 4]; } SolidFillRoundedRectangle(context, bounds, 4, faceColor); HighlightButtonBorder(context, bounds); } /*---------------------------------------------------------------------- * +++ DrawDarkCheckBox -- * * This is a standalone drawing procedure which draws Checkboxes in the * Dark Mode style. */ static void DrawDarkCheckBox( CGRect bounds, Ttk_State state, CGContextRef context) { CGRect checkbounds = {{0, bounds.size.height / 2 - 8}, {16, 16}}; NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *stroke; CGFloat x, y; bounds = CGRectOffset(checkbounds, bounds.origin.x, bounds.origin.y); x = bounds.origin.x; y = bounds.origin.y; CGContextClipToRect(context, bounds); FillButtonBackground(context, bounds, 4); bounds = CGRectInset(bounds, 1, 1); if (!(state & TTK_STATE_BACKGROUND) && !(state & TTK_STATE_DISABLED) && ((state & TTK_STATE_SELECTED) || (state & TTK_STATE_ALTERNATE))) { GradientFillRoundedRectangle(context, bounds, 3, darkSelectedGradient, 2); } else { GradientFillRoundedRectangle(context, bounds, 3, darkInactiveGradient, 2); } HighlightButtonBorder(context, bounds); if ((state & TTK_STATE_SELECTED) || (state & TTK_STATE_ALTERNATE)) { CGContextSetStrokeColorSpace(context, deviceRGB.CGColorSpace); if (state & TTK_STATE_DISABLED) { stroke = [NSColor disabledControlTextColor]; } else { stroke = [NSColor controlTextColor]; } CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); } if (state & TTK_STATE_SELECTED) { CGContextSetLineWidth(context, 1.5); CGContextBeginPath(context); CGPoint check[3] = {{x + 4, y + 8}, {x + 7, y + 11}, {x + 11, y + 4}}; CGContextAddLines(context, check, 3); CGContextStrokePath(context); } else if (state & TTK_STATE_ALTERNATE) { CGContextSetLineWidth(context, 2.0); CGContextBeginPath(context); CGPoint bar[2] = {{x + 4, y + 8}, {x + 12, y + 8}}; CGContextAddLines(context, bar, 2); CGContextStrokePath(context); } } /*---------------------------------------------------------------------- * +++ DrawDarkRadioButton -- * * This is a standalone drawing procedure which draws RadioButtons * in the Dark Mode style. */ static void DrawDarkRadioButton( CGRect bounds, Ttk_State state, CGContextRef context) { CGRect checkbounds = {{0, bounds.size.height / 2 - 9}, {18, 18}}; NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *fill; CGFloat x, y; bounds = CGRectOffset(checkbounds, bounds.origin.x, bounds.origin.y); x = bounds.origin.x; y = bounds.origin.y; CGContextClipToRect(context, bounds); FillButtonBackground(context, bounds, 9); bounds = CGRectInset(bounds, 1, 1); if (!(state & TTK_STATE_BACKGROUND) && !(state & TTK_STATE_DISABLED) && ((state & TTK_STATE_SELECTED) || (state & TTK_STATE_ALTERNATE))) { GradientFillRoundedRectangle(context, bounds, 8, darkSelectedGradient, 2); } else { GradientFillRoundedRectangle(context, bounds, 8, darkInactiveGradient, 2); } HighlightButtonBorder(context, bounds); if ((state & TTK_STATE_SELECTED) || (state & TTK_STATE_ALTERNATE)) { CGContextSetStrokeColorSpace(context, deviceRGB.CGColorSpace); if (state & TTK_STATE_DISABLED) { fill = [NSColor disabledControlTextColor]; } else { fill = [NSColor controlTextColor]; } CGContextSetFillColorWithColor(context, CGCOLOR(fill)); } if (state & TTK_STATE_SELECTED) { CGContextBeginPath(context); CGRect dot = {{x + 6, y + 6}, {6, 6}}; CGContextAddEllipseInRect(context, dot); CGContextFillPath(context); } else if (state & TTK_STATE_ALTERNATE) { CGRect bar = {{x + 5, y + 8}, {8, 2}}; CGContextFillRect(context, bar); } } /*---------------------------------------------------------------------- * +++ DrawDarkTab -- * * This is a standalone drawing procedure which draws Tabbed Pane * Tabs in the Dark Mode style. */ static void DrawDarkTab( CGRect bounds, Ttk_State state, CGContextRef context) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *faceColor, *stroke; CGRect originalBounds = bounds; CGContextSetLineWidth(context, 1.0); CGContextClipToRect(context, bounds); /* * Extend the bounds to one or both sides so the rounded part will be * clipped off. */ if (!(state & TTK_STATE_FIRST_TAB)) { bounds.origin.x -= 10; bounds.size.width += 10; } if (!(state & TTK_STATE_LAST_TAB)) { bounds.size.width += 10; } /* * Fill the tab face with the appropriate color or gradient. Use a solid * color if the tab is not selected, otherwise use a blue or gray * gradient. */ bounds = CGRectInset(bounds, 1, 1); if (!(state & TTK_STATE_SELECTED)) { if (state & TTK_STATE_DISABLED) { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkDisabledButtonFace count: 4]; } else { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkButtonFace count: 4]; } SolidFillRoundedRectangle(context, bounds, 4, faceColor); /* * Draw a separator line on the left side of the tab if it * not first. */ if (!(state & TTK_STATE_FIRST_TAB)) { CGContextSaveGState(context); CGContextSetShouldAntialias(context, false); stroke = [NSColor colorWithColorSpace: deviceRGB components: darkTabSeparator count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); CGContextBeginPath(context); CGContextMoveToPoint(context, originalBounds.origin.x, originalBounds.origin.y + 1); CGContextAddLineToPoint(context, originalBounds.origin.x, originalBounds.origin.y + originalBounds.size.height - 1); CGContextStrokePath(context); CGContextRestoreGState(context); } } else { /* * This is the selected tab; paint it blue. If it is first, cover up * the separator line drawn by the second one. (The selected tab is * always drawn last.) */ if ((state & TTK_STATE_FIRST_TAB) && !(state & TTK_STATE_LAST_TAB)) { bounds.size.width += 1; } if (!(state & TTK_STATE_BACKGROUND)) { GradientFillRoundedRectangle(context, bounds, 4, darkSelectedGradient, 2); } else { faceColor = [NSColor colorWithColorSpace: deviceRGB components: darkInactiveSelectedTab count: 4]; SolidFillRoundedRectangle(context, bounds, 4, faceColor); } HighlightButtonBorder(context, bounds); } } /*---------------------------------------------------------------------- * +++ DrawDarkSeparator -- * * This is a standalone drawing procedure which draws a separator widget * in Dark Mode. */ static void DrawDarkSeparator( CGRect bounds, CGContextRef context, Tk_Window tkwin) { static CGFloat fill[4] = {1.0, 1.0, 1.0, 0.3}; NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *fillColor = [NSColor colorWithColorSpace: deviceRGB components: fill count:4]; CGContextSetFillColorWithColor(context, CGCOLOR(fillColor)); CGContextFillRect(context, bounds); } /*---------------------------------------------------------------------- * +++ DrawDarkFrame -- * * This is a standalone drawing procedure which draws various * types of borders in Dark Mode. */ static void DrawDarkFrame( CGRect bounds, CGContextRef context, HIThemeFrameKind kind) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *stroke; CGContextSetStrokeColorSpace(context, deviceRGB.CGColorSpace); CGFloat x = bounds.origin.x, y = bounds.origin.y; CGFloat w = bounds.size.width, h = bounds.size.height; CGPoint topPart[4] = { {x, y + h - 1}, {x, y}, {x + w, y}, {x + w, y + h - 1} }; CGPoint bottom[2] = {{x, y + h}, {x + w, y + h}}; CGPoint accent[2] = {{x, y + 1}, {x + w, y + 1}}; switch (kind) { case kHIThemeFrameTextFieldSquare: CGContextSaveGState(context); CGContextSetShouldAntialias(context, false); CGContextBeginPath(context); stroke = [NSColor colorWithColorSpace: deviceRGB components: darkFrameTop count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); CGContextAddLines(context, topPart, 4); CGContextStrokePath(context); stroke = [NSColor colorWithColorSpace: deviceRGB components: darkFrameBottom count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); CGContextAddLines(context, bottom, 2); CGContextStrokePath(context); stroke = [NSColor colorWithColorSpace: deviceRGB components: darkFrameAccent count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); CGContextAddLines(context, accent, 2); CGContextStrokePath(context); CGContextRestoreGState(context); break; default: break; } } /*---------------------------------------------------------------------- * +++ DrawListHeader -- * * This is a standalone drawing procedure which draws column * headers for a Treeview in the Dark Mode. */ static void DrawDarkListHeader( CGRect bounds, CGContextRef context, Tk_Window tkwin, int state) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *stroke; CGContextSetStrokeColorSpace(context, deviceRGB.CGColorSpace); CGFloat x = bounds.origin.x, y = bounds.origin.y; CGFloat w = bounds.size.width, h = bounds.size.height; CGPoint top[2] = {{x, y}, {x + w, y}}; CGPoint bottom[2] = {{x, y + h}, {x + w, y + h}}; CGPoint separator[2] = {{x + w, y + 3}, {x + w, y + h - 3}}; CGContextSaveGState(context); CGContextSetShouldAntialias(context, false); stroke = [NSColor colorWithColorSpace: deviceRGB components: darkFrameBottom count: 4]; CGContextSetStrokeColorWithColor(context, CGCOLOR(stroke)); CGContextBeginPath(context); CGContextAddLines(context, top, 2); CGContextStrokePath(context); CGContextAddLines(context, bottom, 2); CGContextStrokePath(context); CGContextAddLines(context, separator, 2); CGContextStrokePath(context); |
︙ | ︙ | |||
1019 1020 1021 1022 1023 1024 1025 | DrawUpArrow(context, arrowBounds, 3, 8, whiteRGBA); } else if (state & TTK_STATE_SELECTED) { DrawDownArrow(context, arrowBounds, 3, 8, whiteRGBA); } } } | < < < | | | | | > | > | | | | | > > | < > > > | | | | | | | > | > > > > > > | > > | > > | | | | | | | | | | | | > > | > > | > | | | | | > > | > > > | < | < > | | | | | | | | | | | < | > < | | | | | < | | | | | | | < | | | | < | | | | | > | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 | DrawUpArrow(context, arrowBounds, 3, 8, whiteRGBA); } else if (state & TTK_STATE_SELECTED) { DrawDownArrow(context, arrowBounds, 3, 8, whiteRGBA); } } } /*---------------------------------------------------------------------- * +++ Button element: Used for elements drawn with DrawThemeButton. */ /* * When Ttk draws the various types of buttons, a pointer to one of these * is passed as the clientData. */ typedef struct { ThemeButtonKind kind; ThemeMetric heightMetric; } ThemeButtonParams; static ThemeButtonParams PushButtonParams = {kThemePushButton, kThemeMetricPushButtonHeight}, CheckBoxParams = {kThemeCheckBox, kThemeMetricCheckBoxHeight}, RadioButtonParams = {kThemeRadioButton, kThemeMetricRadioButtonHeight}, BevelButtonParams = {kThemeRoundedBevelButton, NoThemeMetric}, PopupButtonParams = {kThemePopupButton, kThemeMetricPopupButtonHeight}, DisclosureParams = { kThemeDisclosureButton, kThemeMetricDisclosureTriangleHeight }, ListHeaderParams = {kThemeListHeaderButton, kThemeMetricListHeaderHeight}; static Ttk_StateTable ButtonValueTable[] = { {kThemeButtonMixed, TTK_STATE_ALTERNATE, 0}, {kThemeButtonOn, TTK_STATE_SELECTED, 0}, {kThemeButtonOff, 0, 0} /* * Others: kThemeDisclosureRight, kThemeDisclosureDown, * kThemeDisclosureLeft */ }; static Ttk_StateTable ButtonAdornmentTable[] = { {kThemeAdornmentDefault | kThemeAdornmentFocus, TTK_STATE_ALTERNATE | TTK_STATE_FOCUS, 0}, {kThemeAdornmentDefault, TTK_STATE_ALTERNATE, 0}, {kThemeAdornmentNone, TTK_STATE_ALTERNATE, 0}, {kThemeAdornmentFocus, TTK_STATE_FOCUS, 0}, {kThemeAdornmentNone, 0, 0} }; /*---------------------------------------------------------------------- * +++ computeButtonDrawInfo -- * * Fill in an appearance manager HIThemeButtonDrawInfo record. */ static inline HIThemeButtonDrawInfo computeButtonDrawInfo( ThemeButtonParams *params, Ttk_State state, Tk_Window tkwin) { /* * See ButtonElementDraw for the explanation of why we always draw * PushButtons in the active state. */ SInt32 HIThemeState; switch (params->kind) { case kThemePushButton: HIThemeState = kThemeStateActive; break; default: HIThemeState = Ttk_StateTableLookup(ThemeStateTable, state); break; } const HIThemeButtonDrawInfo info = { .version = 0, .state = HIThemeState, .kind = params ? params->kind : 0, .value = Ttk_StateTableLookup(ButtonValueTable, state), .adornment = Ttk_StateTableLookup(ButtonAdornmentTable, state), }; return info; } /*---------------------------------------------------------------------- * +++ Button elements. */ static void ButtonElementMinSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { ThemeButtonParams *params = clientData; if (params->heightMetric != NoThemeMetric) { ChkErr(GetThemeMetric, params->heightMetric, minHeight); /* * The theme height does not include the 1-pixel border around * the button, although it does include the 1-pixel shadow at * the bottom. */ *minHeight += 2; /* * The minwidth must be 0 to force the generic ttk code to compute the * correct text layout. For example, a non-zero value will cause the * text to be left justified, no matter what -anchor setting is used in * the style. */ *minWidth = 0; } } static void ButtonElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { ThemeButtonParams *params = clientData; const HIThemeButtonDrawInfo info = computeButtonDrawInfo(params, 0, tkwin); static const CGRect scratchBounds = {{0, 0}, {100, 100}}; CGRect contentBounds, backgroundBounds; int verticalPad; ButtonElementMinSize(clientData, elementRecord, tkwin, minWidth, minHeight, paddingPtr); /* * Given a hypothetical bounding rectangle for a button, HIToolbox will * compute a bounding rectangle for the button contents and a bounding * rectangle for the button background. The background bounds are large * enough to contain the image of the button in any state, which might * include highlight borders, shadows, etc. The content rectangle is not * centered vertically within the background rectangle, presumably because * shadows only appear on the bottom. Nonetheless, when HITools is asked * to draw a button with a certain bounding rectangle it draws the button * centered within the rectangle. * * To compute the effective padding around a button we request the * content and bounding rectangles for a 100x100 button and use the * padding between those. However, we symmetrize the padding on the * top and bottom, because that is how the button will be drawn. */ ChkErr(HIThemeGetButtonContentBounds, &scratchBounds, &info, &contentBounds); ChkErr(HIThemeGetButtonBackgroundBounds, &scratchBounds, &info, &backgroundBounds); paddingPtr->left = contentBounds.origin.x - backgroundBounds.origin.x; paddingPtr->right = CGRectGetMaxX(backgroundBounds) - CGRectGetMaxX(contentBounds); verticalPad = backgroundBounds.size.height - contentBounds.size.height; paddingPtr->top = paddingPtr->bottom = verticalPad / 2; } static void ButtonElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { ThemeButtonParams *params = clientData; CGRect bounds = BoxToRect(d, b); HIThemeButtonDrawInfo info = computeButtonDrawInfo(params, state, tkwin); bounds = NormalizeButtonBounds(params->heightMetric, bounds); BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { switch (info.kind) { case kThemePushButton: case kThemePopupButton: DrawDarkButton(bounds, info.kind, state, dc.context); break; case kThemeCheckBox: DrawDarkCheckBox(bounds, state, dc.context); break; case kThemeRadioButton: DrawDarkRadioButton(bounds, state, dc.context); break; case kThemeRoundedBevelButton: DrawDarkBevelButton(bounds, state, dc.context); break; default: ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } } else { /* * Apple's PushButton and PopupButton do not change their fill color * when the window is inactive. However, except in 10.7 (Lion), the * color of the arrow button on a PopupButton does change. For some * reason HITheme fills inactive buttons with a transparent color that * allows the window background to show through, leading to * inconsistent behavior. We work around this by filling behind an * inactive PopupButton with a text background color before asking * HIToolbox to draw it. For PushButtons, we simply draw them in the * active state. */ if (info.kind == kThemePopupButton && (state & TTK_STATE_BACKGROUND)) { CGRect innerBounds = CGRectInset(bounds, 1, 1); NSColor *whiteRGBA = [NSColor whiteColor]; SolidFillRoundedRectangle(dc.context, innerBounds, 4, whiteRGBA); } /* * A BevelButton with mixed value is drawn borderless, which does make * much sense for us. */ if (info.kind == kThemeRoundedBevelButton && info.value == kThemeButtonMixed) { info.value = kThemeButtonOff; info.state = kThemeStateInactive; } ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec ButtonElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, ButtonElementSize, ButtonElementDraw }; /*---------------------------------------------------------------------- * +++ Notebook elements. */ /* Tab position logic, c.f. ttkNotebook.c TabState() */ static Ttk_StateTable TabStyleTable[] = { {kThemeTabFrontInactive, TTK_STATE_SELECTED | TTK_STATE_BACKGROUND}, {kThemeTabNonFrontInactive, TTK_STATE_BACKGROUND}, {kThemeTabFrontUnavailable, TTK_STATE_DISABLED | TTK_STATE_SELECTED}, {kThemeTabNonFrontUnavailable, TTK_STATE_DISABLED}, {kThemeTabFront, TTK_STATE_SELECTED}, {kThemeTabNonFrontPressed, TTK_STATE_PRESSED}, {kThemeTabNonFront, 0} }; static Ttk_StateTable TabAdornmentTable[] = { {kHIThemeTabAdornmentNone, TTK_STATE_FIRST_TAB | TTK_STATE_LAST_TAB}, {kHIThemeTabAdornmentTrailingSeparator, TTK_STATE_FIRST_TAB}, {kHIThemeTabAdornmentNone, TTK_STATE_LAST_TAB}, {kHIThemeTabAdornmentTrailingSeparator, 0}, }; static Ttk_StateTable TabPositionTable[] = { {kHIThemeTabPositionOnly, TTK_STATE_FIRST_TAB | TTK_STATE_LAST_TAB}, {kHIThemeTabPositionFirst, TTK_STATE_FIRST_TAB}, {kHIThemeTabPositionLast, TTK_STATE_LAST_TAB}, {kHIThemeTabPositionMiddle, 0}, }; /* * Apple XHIG Tab View Specifications: * * Control sizes: Tab views are available in regular, small, and mini sizes. * The tab height is fixed for each size, but you control the size of the pane * area. The tab heights for each size are listed below: * - Regular size: 20 pixels. * - Small: 17 pixels. * - Mini: 15 pixels. * * Label spacing and fonts: The tab labels should be in a font that’s * proportional to the size of the tab view control. In addition, the label * should be placed so that there are equal margins of space before and after * it. The guidelines below provide the specifications you should use for tab * labels: * - Regular size: System font. Center in tab, leaving 12 pixels on each *side. * - Small: Small system font. Center in tab, leaving 10 pixels on each side. * - Mini: Mini system font. Center in tab, leaving 8 pixels on each side. * * Control spacing: Whether you decide to inset a tab view in a window or * extend its edges to the window sides and bottom, you should place the top * edge of the tab view 12 or 14 pixels below the bottom edge of the title bar * (or toolbar, if there is one). If you choose to inset a tab view in a |
︙ | ︙ | |||
1310 1311 1312 1313 1314 1315 1316 | * * <URL: http://developer.apple.com/documentation/userexperience/Conceptual/ * AppleHIGuidelines/XHIGControls/XHIGControls.html#//apple_ref/doc/uid/ * TP30000359-TPXREF116> */ static void TabElementSize( | | > > | > > | | > > | > > > < | > < < < | > > | > > | > > | > > > < > | | | | | | | | | | | | | < > | | > | | < | | > > | > > | > > | > > | | | | | | | | | < > | > | | | | | | | > > | > > | > > | > > < | | | < | | | | | | | | | > | | | > | < | | | < > < < < | | | | | | | | | | | | | | | | > > | > > | > > | > > < | < | < < | | < | > | | | | | | | | | | | | | | | | > | > > | > > | | > > | > > > < | < < | > < | > > | > > | > > | > > > < | < < | > > | | | | | | | | | | | | | | | < | > > | > > | | > > | > > | | | < | | | | < | | > < < > | > > | > > | | | | | | | | | | | | | | | | | < | > > | > > | | > > | > > > > | | | | < | | | | < | | | | < | > > | > > | | | | | > > | > > | > > | | > | > > | > > > | | < | < | < | > > | > > | | > > | > > > | | | | < | | | | | | < | | | | | | > | | | > | | | | | | < | > > | > > | 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 | * * <URL: http://developer.apple.com/documentation/userexperience/Conceptual/ * AppleHIGuidelines/XHIGControls/XHIGControls.html#//apple_ref/doc/uid/ * TP30000359-TPXREF116> */ static void TabElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { GetThemeMetric(kThemeMetricLargeTabHeight, (SInt32 *) minHeight); *paddingPtr = Ttk_MakePadding(0, 0, 0, 2); } static void TabElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, b); HIThemeTabDrawInfo info = { .version = 1, .style = Ttk_StateTableLookup(TabStyleTable, state), .direction = kThemeTabNorth, .size = kHIThemeTabSizeNormal, .adornment = Ttk_StateTableLookup(TabAdornmentTable, state), .kind = kHIThemeTabKindNormal, .position = Ttk_StateTableLookup(TabPositionTable, state), }; BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { DrawDarkTab(bounds, state, dc.context); } else { ChkErr(HIThemeDrawTab, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec TabElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TabElementSize, TabElementDraw }; /* * Notebook panes: */ static void PaneElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *paddingPtr = Ttk_MakePadding(9, 5, 9, 9); } static void PaneElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, b); bounds.origin.y -= kThemeMetricTabFrameOverlap; bounds.size.height += kThemeMetricTabFrameOverlap; BEGIN_DRAWING(d) if ([NSApp macMinorVersion] > 8) { DrawGroupBox(bounds, dc.context, tkwin); } else { HIThemeTabPaneDrawInfo info = { .version = 1, .state = Ttk_StateTableLookup(ThemeStateTable, state), .direction = kThemeTabNorth, .size = kHIThemeTabSizeNormal, .kind = kHIThemeTabKindNormal, .adornment = kHIThemeTabPaneAdornmentNormal, }; bounds.origin.y -= kThemeMetricTabFrameOverlap; bounds.size.height += kThemeMetricTabFrameOverlap; ChkErr(HIThemeDrawTabPane, &bounds, &info, dc.context, HIOrientation); } END_DRAWING } static Ttk_ElementSpec PaneElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, PaneElementSize, PaneElementDraw }; /*---------------------------------------------------------------------- * +++ Labelframe elements -- * * Labelframe borders: Use "primary group box ..." Quoth * DrawThemePrimaryGroup reference: "The primary group box frame is drawn * inside the specified rectangle and is a maximum of 2 pixels thick." * * "Maximum of 2 pixels thick" is apparently a lie; looks more like 4 to me * with shading. */ static void GroupElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *paddingPtr = Ttk_UniformPadding(4); } static void GroupElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, b); BEGIN_DRAWING(d) if ([NSApp macMinorVersion] > 8) { DrawGroupBox(bounds, dc.context, tkwin); } else { const HIThemeGroupBoxDrawInfo info = { .version = 0, .state = Ttk_StateTableLookup(ThemeStateTable, state), .kind = kHIThemeGroupBoxKindPrimaryOpaque, }; ChkErr(HIThemeDrawGroupBox, &bounds, &info, dc.context, HIOrientation); } END_DRAWING } static Ttk_ElementSpec GroupElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, GroupElementSize, GroupElementDraw }; /*---------------------------------------------------------------------- * +++ Entry elements -- * * 3 pixels padding for focus rectangle * 2 pixels padding for EditTextFrame */ typedef struct { Tcl_Obj *backgroundObj; Tcl_Obj *fieldbackgroundObj; } EntryElement; #define ENTRY_DEFAULT_BACKGROUND "systemTextBackgroundColor" static Ttk_ElementOptionSpec EntryElementOptions[] = { {"-background", TK_OPTION_BORDER, Tk_Offset(EntryElement, backgroundObj), ENTRY_DEFAULT_BACKGROUND}, {"-fieldbackground", TK_OPTION_BORDER, Tk_Offset(EntryElement, fieldbackgroundObj), ENTRY_DEFAULT_BACKGROUND}, {0} }; static void EntryElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *paddingPtr = Ttk_UniformPadding(5); } static void EntryElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { EntryElement *e = elementRecord; Ttk_Box inner = Ttk_PadBox(b, Ttk_UniformPadding(3)); CGRect bounds = BoxToRect(d, inner); NSColor *background; Tk_3DBorder backgroundPtr = NULL; static const char *defaultBG = ENTRY_DEFAULT_BACKGROUND; if (TkMacOSXInDarkMode(tkwin)) { BEGIN_DRAWING(d) NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; CGFloat fill[4]; GetBackgroundColor(dc.context, tkwin, 1, fill); background = [NSColor colorWithColorSpace: deviceRGB components: fill count: 4]; CGContextSetFillColorWithColor(dc.context, CGCOLOR(background)); CGContextFillRect(dc.context, bounds); DrawDarkFrame(bounds, dc.context, kHIThemeFrameTextFieldSquare); END_DRAWING } else { const HIThemeFrameDrawInfo info = { .version = 0, .kind = kHIThemeFrameTextFieldSquare, .state = Ttk_StateTableLookup(ThemeStateTable, state), .isFocused = state & TTK_STATE_FOCUS, }; /* * Earlier versions of the Aqua theme ignored the -fieldbackground * option and used the -background as if it were -fieldbackground. * Here we are enabling -fieldbackground. For backwards * compatibility, if -fieldbackground is set to the default color and * -background is set to a different color then we use -background as * -fieldbackground. */ if (0 != strcmp(Tcl_GetString(e->fieldbackgroundObj), defaultBG)) { backgroundPtr = Tk_Get3DBorderFromObj(tkwin, e->fieldbackgroundObj); } else if (0 != strcmp(Tcl_GetString(e->backgroundObj), defaultBG)) { backgroundPtr = Tk_Get3DBorderFromObj(tkwin, e->backgroundObj); } if (backgroundPtr != NULL) { XFillRectangle(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC), inner.x, inner.y, inner.width, inner.height); } BEGIN_DRAWING(d) if (backgroundPtr == NULL) { if ([NSApp macMinorVersion] > 8) { background = [NSColor textBackgroundColor]; CGContextSetFillColorWithColor(dc.context, CGCOLOR(background)); } else { CGContextSetRGBFillColor(dc.context, 1.0, 1.0, 1.0, 1.0); } CGContextFillRect(dc.context, bounds); } ChkErr(HIThemeDrawFrame, &bounds, &info, dc.context, HIOrientation); END_DRAWING } } static Ttk_ElementSpec EntryElementSpec = { TK_STYLE_VERSION_2, sizeof(EntryElement), EntryElementOptions, EntryElementSize, EntryElementDraw }; /*---------------------------------------------------------------------- * +++ Combobox elements -- * * NOTES: * The HIToolbox has incomplete and inconsistent support for ComboBoxes. * There is no constant available to get the height of a ComboBox with * GetThemeMetric. In fact, ComboBoxes are the same (fixed) height as * PopupButtons and PushButtons, but they have no shadow at the bottom. * As a result, they are drawn 1 pixel above the center of the bounds * rectangle rather than being centered like the other buttons. One can * request background bounds for a ComboBox, and it is reported with * height 23, while the actual button face, including its 1-pixel border * has height 21. Attempting to request the content bounds returns a 0x0 * rectangle. Measurement indicates that the arrow button has width 18. * * With no help available from HIToolbox, we have to use hard-wired * constants for the padding. We shift the bounding rectangle downward by * 1 pixel to account for the fact that the button is not centered. */ static Ttk_Padding ComboboxPadding = {4, 2, 20, 2}; static void ComboboxElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *minWidth = 24; *minHeight = 23; *paddingPtr = ComboboxPadding; } static void ComboboxElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, b); const HIThemeButtonDrawInfo info = { .version = 0, .state = Ttk_StateTableLookup(ThemeStateTable, state), .kind = kThemeComboBox, .value = Ttk_StateTableLookup(ButtonValueTable, state), .adornment = Ttk_StateTableLookup(ButtonAdornmentTable, state), }; BEGIN_DRAWING(d) bounds.origin.y += 1; if (TkMacOSXInDarkMode(tkwin)) { bounds.size.height += 1; DrawDarkButton(bounds, info.kind, state, dc.context); } else if ([NSApp macMinorVersion] > 8) { if ((state & TTK_STATE_BACKGROUND) && !(state & TTK_STATE_DISABLED)) { NSColor *background = [NSColor textBackgroundColor]; CGRect innerBounds = CGRectInset(bounds, 1, 2); SolidFillRoundedRectangle(dc.context, innerBounds, 4, background); } ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec ComboboxElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, ComboboxElementSize, ComboboxElementDraw }; /*---------------------------------------------------------------------- * +++ Spinbutton elements -- * * From Apple HIG, part III, section "Controls", "The Stepper Control": * there should be 2 pixels of space between the stepper control (AKA * IncDecButton, AKA "little arrows") and the text field it modifies. * * Ttk expects the up and down arrows to be distinct elements but * HIToolbox draws them as one widget with two different pressed states. * We work around this by defining them as separate elements in the * layout, but making each one have a drawing method which also draws the * other one. The down button does no drawing when not pressed, and when * pressed draws the entire IncDecButton in its "pressed down" state. * The up button draws the entire IncDecButton when not pressed and when * pressed draws the IncDecButton in its "pressed up" state. NOTE: This * means that when the down button is pressed the IncDecButton will be * drawn twice, first in unpressed state by the up arrow and then in * "pressed down" state by the down button. The drawing must be done in * that order. So the up button must be listed first in the layout. */ static Ttk_Padding SpinbuttonMargins = {0, 0, 2, 0}; static void SpinButtonUpElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { SInt32 s; ChkErr(GetThemeMetric, kThemeMetricLittleArrowsWidth, &s); *minWidth = s + Ttk_PaddingWidth(SpinbuttonMargins); ChkErr(GetThemeMetric, kThemeMetricLittleArrowsHeight, &s); *minHeight = (s + Ttk_PaddingHeight(SpinbuttonMargins)) / 2; } static void SpinButtonUpElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, Ttk_PadBox(b, SpinbuttonMargins)); int infoState; bounds.size.height *= 2; if (state & TTK_STATE_PRESSED) { infoState = kThemeStatePressedUp; } else { infoState = Ttk_StateTableLookup(ThemeStateTable, state); } const HIThemeButtonDrawInfo info = { .version = 0, .state = infoState, .kind = kThemeIncDecButton, .value = Ttk_StateTableLookup(ButtonValueTable, state), .adornment = kThemeAdornmentNone, }; BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { DrawDarkIncDecButton(bounds, infoState, state, dc.context); } else { ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec SpinButtonUpElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, SpinButtonUpElementSize, SpinButtonUpElementDraw }; static void SpinButtonDownElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { SInt32 s; ChkErr(GetThemeMetric, kThemeMetricLittleArrowsWidth, &s); *minWidth = s + Ttk_PaddingWidth(SpinbuttonMargins); ChkErr(GetThemeMetric, kThemeMetricLittleArrowsHeight, &s); *minHeight = (s + Ttk_PaddingHeight(SpinbuttonMargins)) / 2; } static void SpinButtonDownElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, Ttk_PadBox(b, SpinbuttonMargins)); int infoState = 0; bounds.origin.y -= bounds.size.height; bounds.size.height *= 2; if (state & TTK_STATE_PRESSED) { infoState = kThemeStatePressedDown; } else { return; } const HIThemeButtonDrawInfo info = { .version = 0, .state = infoState, .kind = kThemeIncDecButton, .value = Ttk_StateTableLookup(ButtonValueTable, state), .adornment = kThemeAdornmentNone, }; BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { DrawDarkIncDecButton(bounds, infoState, state, dc.context); } else { ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec SpinButtonDownElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, SpinButtonDownElementSize, SpinButtonDownElementDraw }; /*---------------------------------------------------------------------- * +++ DrawThemeTrack-based elements -- * * Progress bars and scales. (See also: <<NOTE-TRACKS>>) */ /* * Apple does not change the appearance of a slider when the window becomes * inactive. So we shouldn't either. */ static Ttk_StateTable ThemeTrackEnableTable[] = { {kThemeTrackDisabled, TTK_STATE_DISABLED, 0}, {kThemeTrackActive, TTK_STATE_BACKGROUND, 0}, {kThemeTrackActive, 0, 0} /* { kThemeTrackNothingToScroll, ?, ? }, */ }; typedef struct { /* TrackElement client data */ ThemeTrackKind kind; SInt32 thicknessMetric; } TrackElementData; static TrackElementData ScaleData = { kThemeSlider, kThemeMetricHSliderHeight }; typedef struct { Tcl_Obj *fromObj; /* minimum value */ Tcl_Obj *toObj; /* maximum value */ Tcl_Obj *valueObj; /* current value */ Tcl_Obj *orientObj; /* horizontal / vertical */ } TrackElement; static Ttk_ElementOptionSpec TrackElementOptions[] = { {"-from", TK_OPTION_DOUBLE, Tk_Offset(TrackElement, fromObj)}, {"-to", TK_OPTION_DOUBLE, Tk_Offset(TrackElement, toObj)}, {"-value", TK_OPTION_DOUBLE, Tk_Offset(TrackElement, valueObj)}, {"-orient", TK_OPTION_STRING, Tk_Offset(TrackElement, orientObj)}, {0, 0, 0} }; static void TrackElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { TrackElementData *data = clientData; SInt32 size = 24; /* reasonable default ... */ ChkErr(GetThemeMetric, data->thicknessMetric, &size); *minWidth = *minHeight = size; } static void TrackElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { TrackElementData *data = clientData; TrackElement *elem = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL; double from = 0, to = 100, value = 0, factor; Ttk_GetOrientFromObj(NULL, elem->orientObj, &orientation); Tcl_GetDoubleFromObj(NULL, elem->fromObj, &from); Tcl_GetDoubleFromObj(NULL, elem->toObj, &to); Tcl_GetDoubleFromObj(NULL, elem->valueObj, &value); factor = RangeToFactor(to - from); HIThemeTrackDrawInfo info = { .version = 0, .kind = data->kind, .bounds = BoxToRect(d, b), .min = from * factor, .max = to * factor, .value = value * factor, .attributes = kThemeTrackShowThumb | (orientation == TTK_ORIENT_HORIZONTAL ? kThemeTrackHorizontal : 0), .enableState = Ttk_StateTableLookup(ThemeTrackEnableTable, state), .trackInfo.progress.phase = 0, }; if (info.kind == kThemeSlider) { info.trackInfo.slider.pressState = state & TTK_STATE_PRESSED ? kThemeThumbPressed : 0; if (state & TTK_STATE_ALTERNATE) { info.trackInfo.slider.thumbDir = kThemeThumbDownward; } else { info.trackInfo.slider.thumbDir = kThemeThumbPlain; } } BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { CGRect bounds = BoxToRect(d, b); NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *trackColor = [NSColor colorWithColorSpace: deviceRGB components: darkTrack count: 4]; if (orientation == TTK_ORIENT_HORIZONTAL) { bounds = CGRectInset(bounds, 1, bounds.size.height / 2 - 2); } else { bounds = CGRectInset(bounds, bounds.size.width / 2 - 3, 2); } SolidFillRoundedRectangle(dc.context, bounds, 2, trackColor); } ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation); END_DRAWING } static Ttk_ElementSpec TrackElementSpec = { TK_STYLE_VERSION_2, sizeof(TrackElement), TrackElementOptions, TrackElementSize, TrackElementDraw }; /*---------------------------------------------------------------------- * Slider elements -- <<NOTE-TRACKS>> * * Has geometry only. The Scale widget adjusts the position of this element, * and uses it for hit detection. In the Aqua theme, the slider is actually * drawn as part of the trough element. * */ static void SliderElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *minWidth = *minHeight = 24; } static Ttk_ElementSpec SliderElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, SliderElementSize, TtkNullElementDraw }; /*---------------------------------------------------------------------- * +++ Progress bar elements -- * * @@@ NOTE: According to an older revision of the Aqua reference docs, * @@@ the 'phase' field is between 0 and 4. Newer revisions say * @@@ that it can be any UInt8 value. */ typedef struct { Tcl_Obj *orientObj; /* horizontal / vertical */ Tcl_Obj *valueObj; /* current value */ Tcl_Obj *maximumObj; /* maximum value */ Tcl_Obj *phaseObj; /* animation phase */ Tcl_Obj *modeObj; /* progress bar mode */ } PbarElement; static Ttk_ElementOptionSpec PbarElementOptions[] = { {"-orient", TK_OPTION_STRING, Tk_Offset(PbarElement, orientObj), "horizontal"}, {"-value", TK_OPTION_DOUBLE, Tk_Offset(PbarElement, valueObj), "0"}, {"-maximum", TK_OPTION_DOUBLE, Tk_Offset(PbarElement, maximumObj), "100"}, {"-phase", TK_OPTION_INT, Tk_Offset(PbarElement, phaseObj), "0"}, {"-mode", TK_OPTION_STRING, Tk_Offset(PbarElement, modeObj), "determinate"}, {0, 0, 0, 0} }; static void PbarElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { SInt32 size = 24; /* @@@ Check HIG for correct default */ ChkErr(GetThemeMetric, kThemeMetricLargeProgressBarThickness, &size); *minWidth = *minHeight = size; } static void PbarElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { PbarElement *pbar = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL, phase = 0; double value = 0, maximum = 100, factor; Ttk_GetOrientFromObj(NULL, pbar->orientObj, &orientation); Tcl_GetDoubleFromObj(NULL, pbar->valueObj, &value); Tcl_GetDoubleFromObj(NULL, pbar->maximumObj, &maximum); Tcl_GetIntFromObj(NULL, pbar->phaseObj, &phase); factor = RangeToFactor(maximum); HIThemeTrackDrawInfo info = { .version = 0, .kind = (!strcmp("indeterminate", Tcl_GetString(pbar->modeObj)) && value) ? kThemeIndeterminateBar : kThemeProgressBar, .bounds = BoxToRect(d, b), .min = 0, .max = maximum * factor, .value = value * factor, .attributes = kThemeTrackShowThumb | (orientation == TTK_ORIENT_HORIZONTAL ? kThemeTrackHorizontal : 0), .enableState = Ttk_StateTableLookup(ThemeTrackEnableTable, state), .trackInfo.progress.phase = phase, }; BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { CGRect bounds = BoxToRect(d, b); NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *trackColor = [NSColor colorWithColorSpace: deviceRGB components: darkTrack count: 4]; if (orientation == TTK_ORIENT_HORIZONTAL) { bounds = CGRectInset(bounds, 1, bounds.size.height / 2 - 3); } else { bounds = CGRectInset(bounds, bounds.size.width / 2 - 3, 1); } SolidFillRoundedRectangle(dc.context, bounds, 3, trackColor); } ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation); END_DRAWING } static Ttk_ElementSpec PbarElementSpec = { TK_STYLE_VERSION_2, sizeof(PbarElement), PbarElementOptions, PbarElementSize, PbarElementDraw }; /*---------------------------------------------------------------------- * +++ Scrollbar elements */ typedef struct { Tcl_Obj *orientObj; } ScrollbarElement; static Ttk_ElementOptionSpec ScrollbarElementOptions[] = { {"-orient", TK_OPTION_STRING, Tk_Offset(ScrollbarElement, orientObj), "horizontal"}, {0, 0, 0, 0} }; static void TroughElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { ScrollbarElement *scrollbar = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL; SInt32 thickness = 15; Ttk_GetOrientFromObj(NULL, scrollbar->orientObj, &orientation); ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &thickness); if (orientation == TTK_ORIENT_HORIZONTAL) { *minHeight = thickness; if ([NSApp macMinorVersion] > 7) { *paddingPtr = Ttk_MakePadding(4, 4, 4, 3); } } else { *minWidth = thickness; if ([NSApp macMinorVersion] > 7) { *paddingPtr = Ttk_MakePadding(4, 4, 3, 4); } } } static CGFloat lightTrough[4] = {250.0 / 255, 250.0 / 255, 250.0 / 255, 1.0}; static CGFloat darkTrough[4] = {45.0 / 255, 46.0 / 255, 49.0 / 255, 1.0}; static CGFloat lightInactiveThumb[4] = { 200.0 / 255, 200.0 / 255, 200.0 / 255, 1.0 }; static CGFloat lightActiveThumb[4] = { 133.0 / 255, 133.0 / 255, 133.0 / 255, 1.0 }; static CGFloat darkInactiveThumb[4] = { 116.0 / 255, 117.0 / 255, 118.0 / 255, 1.0 }; static CGFloat darkActiveThumb[4] = { 158.0 / 255, 158.0 / 255, 159.0 / 255, 1.0 }; static void TroughElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { ScrollbarElement *scrollbar = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL; CGRect bounds = BoxToRect(d, b); NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *troughColor; CGFloat *rgba = TkMacOSXInDarkMode(tkwin) ? darkTrough : lightTrough; Ttk_GetOrientFromObj(NULL, scrollbar->orientObj, &orientation); if (orientation == TTK_ORIENT_HORIZONTAL) { bounds = CGRectInset(bounds, 0, 1); } else { bounds = CGRectInset(bounds, 1, 0); } troughColor = [NSColor colorWithColorSpace: deviceRGB components: rgba count: 4]; BEGIN_DRAWING(d) if ([NSApp macMinorVersion] > 8) { CGContextSetFillColorWithColor(dc.context, CGCOLOR(troughColor)); } else { ChkErr(HIThemeSetFill, kThemeBrushDocumentWindowBackground, NULL, dc.context, HIOrientation); } CGContextFillRect(dc.context, bounds); END_DRAWING } static Ttk_ElementSpec TroughElementSpec = { TK_STYLE_VERSION_2, sizeof(ScrollbarElement), ScrollbarElementOptions, TroughElementSize, TroughElementDraw }; static void ThumbElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { ScrollbarElement *scrollbar = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL; Ttk_GetOrientFromObj(NULL, scrollbar->orientObj, &orientation); if (orientation == TTK_ORIENT_HORIZONTAL) { *minHeight = 8; } else { *minWidth = 8; } } static void ThumbElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { ScrollbarElement *scrollbar = elementRecord; int orientation = TTK_ORIENT_HORIZONTAL; Ttk_GetOrientFromObj(NULL, scrollbar->orientObj, &orientation); /* * In order to make ttk scrollbars work correctly it is necessary to be * able to display the thumb element at the size and location which the ttk * scrollbar widget requests. The algorithm that HIToolbox uses to * determine the thumb geometry from the input values of min, max, value * and viewSize is, of course, undocumented. And this turns out to be a * hard reverse engineering problem. A seemingly natural algorithm is * implemented below, but it does not correctly compute the same thumb * geometry as HITools (which also apparently does not agree with * NSScrollbar). This code uses that algorithm for older OS versions, * because using HITools also handles drawing the buttons and 3D thumb used * on those systems. The incorrect geometry is annoying but not completely * unusable. For newer systems the cleanest approach is to just draw the * thumb directly. */ if ([NSApp macMinorVersion] > 8) { CGRect thumbBounds = BoxToRect(d, b); NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *thumbColor; CGFloat *rgba; if ((orientation == TTK_ORIENT_HORIZONTAL && thumbBounds.size.width >= Tk_Width(tkwin) - 8) || (orientation == TTK_ORIENT_VERTICAL && thumbBounds.size.height >= Tk_Height(tkwin) - 8)) { return; } int isDark = TkMacOSXInDarkMode(tkwin); if ((state & TTK_STATE_PRESSED) || (state & TTK_STATE_HOVER)) { rgba = isDark ? darkActiveThumb : lightActiveThumb; } else { rgba = isDark ? darkInactiveThumb : lightInactiveThumb; } thumbColor = [NSColor colorWithColorSpace: deviceRGB components: rgba count: 4]; BEGIN_DRAWING(d) SolidFillRoundedRectangle(dc.context, thumbBounds, 4, thumbColor); END_DRAWING } else { double thumbSize, trackSize, visibleSize, viewSize; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tkwin); CGRect troughBounds = {{macWin->xOff, macWin->yOff}, {Tk_Width(tkwin), Tk_Height(tkwin)}}; /* * The info struct has integer fields, which will be converted to * floats in the drawing routine. All of values provided in the info * struct, namely min, max, value, and viewSize are only defined up to * an arbitrary scale factor. To avoid roundoff error we scale so * that the viewSize is a large float which is smaller than the * largest int. */ viewSize = RangeToFactor(100.0); HIThemeTrackDrawInfo info = { .version = 0, .bounds = troughBounds, .min = 0, .attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost, .enableState = kThemeTrackActive }; info.trackInfo.scrollbar.viewsize = viewSize * .8; if (orientation == TTK_ORIENT_HORIZONTAL) { trackSize = troughBounds.size.width; thumbSize = b.width; visibleSize = (thumbSize / trackSize) * viewSize; info.max = viewSize - visibleSize; info.value = info.max * (b.x / (trackSize - thumbSize)); } else { thumbSize = b.height; trackSize = troughBounds.size.height; visibleSize = (thumbSize / trackSize) * viewSize; info.max = viewSize - visibleSize; info.value = info.max * (b.y / (trackSize - thumbSize)); } if ((state & TTK_STATE_PRESSED) || (state & TTK_STATE_HOVER)) { info.trackInfo.scrollbar.pressState = kThemeThumbPressed; } else { info.trackInfo.scrollbar.pressState = 0; } if (orientation == TTK_ORIENT_HORIZONTAL) { info.attributes |= kThemeTrackHorizontal; } else { info.attributes &= ~kThemeTrackHorizontal; } BEGIN_DRAWING(d) HIThemeDrawTrack(&info, 0, dc.context, kHIThemeOrientationNormal); END_DRAWING } } static Ttk_ElementSpec ThumbElementSpec = { TK_STYLE_VERSION_2, sizeof(ScrollbarElement), ScrollbarElementOptions, ThumbElementSize, ThumbElementDraw }; static void ArrowElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { if ([NSApp macMinorVersion] < 8) { *minHeight = *minWidth = 14; } else { *minHeight = *minWidth = -1; } } |
︙ | ︙ | |||
2228 2229 2230 2231 2232 2233 2234 | * * DrawThemeSeparator() guesses the orientation of the line from the width * and height of the rectangle, so the same element can can be used for * horizontal, vertical, and general separators. */ static void SeparatorElementSize( | | > > | > > | > > > > | | | > < | > < < < | | | > > | > > | > > > > | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | > > | > > | > | | | | | | | | | | | | | | | | | | < > | > > > > | | < | | > > | > > | > | | | | | | > > | > > | > > | | | > | > > | | | > | | | | | | | | | > > | > > | > < | > > | > > | | > > | > > < | | | | | < < < | > | | | | | | < | > > | > > | > > | > > | > | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | > | | | | > > | > | | | > | > | > | > | | | | > | > | > | > | > | > | > | > | > | | 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 | * * DrawThemeSeparator() guesses the orientation of the line from the width * and height of the rectangle, so the same element can can be used for * horizontal, vertical, and general separators. */ static void SeparatorElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { *minWidth = *minHeight = 1; } static void SeparatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { CGRect bounds = BoxToRect(d, b); const HIThemeSeparatorDrawInfo info = { .version = 0, /* Separator only supports kThemeStateActive, kThemeStateInactive */ .state = Ttk_StateTableLookup(ThemeStateTable, state & TTK_STATE_BACKGROUND), }; BEGIN_DRAWING(d) if (TkMacOSXInDarkMode(tkwin)) { DrawDarkSeparator(bounds, dc.context, tkwin); } else { ChkErr(HIThemeDrawSeparator, &bounds, &info, dc.context, HIOrientation); } END_DRAWING } static Ttk_ElementSpec SeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, SeparatorElementSize, SeparatorElementDraw }; /*---------------------------------------------------------------------- * +++ Size grip elements -- (obsolete) */ static const ThemeGrowDirection sizegripGrowDirection = kThemeGrowRight | kThemeGrowDown; static void SizegripElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { HIThemeGrowBoxDrawInfo info = { .version = 0, .state = kThemeStateActive, .kind = kHIThemeGrowBoxKindNormal, .direction = sizegripGrowDirection, .size = kHIThemeGrowBoxSizeNormal, }; CGRect bounds = CGRectZero; ChkErr(HIThemeGetGrowBoxBounds, &bounds.origin, &info, &bounds); *minWidth = bounds.size.width; *minHeight = bounds.size.height; } static void SizegripElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { CGRect bounds = BoxToRect(d, b); HIThemeGrowBoxDrawInfo info = { .version = 0, /* Grow box only supports kThemeStateActive, kThemeStateInactive */ .state = Ttk_StateTableLookup(ThemeStateTable, state & TTK_STATE_BACKGROUND), .kind = kHIThemeGrowBoxKindNormal, .direction = sizegripGrowDirection, .size = kHIThemeGrowBoxSizeNormal, }; BEGIN_DRAWING(d) ChkErr(HIThemeDrawGrowBox, &bounds.origin, &info, dc.context, HIOrientation); END_DRAWING } static Ttk_ElementSpec SizegripElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, SizegripElementSize, SizegripElementDraw }; /*---------------------------------------------------------------------- * +++ Background and fill elements -- * * Before drawing any ttk widget, its bounding rectangle is filled with a * background color. This color must match the background color of the * containing widget to avoid looking ugly. The need for care when doing * this is exacerbated by the fact that ttk enforces its "native look" by * not allowing user control of the background or highlight colors of ttk * widgets. * * This job is made more complicated in recent versions of macOS by the * fact that the Appkit GroupBox (used for ttk LabelFrames) and * TabbedPane (used for the Notebook widget) both place their content * inside a rectangle with rounded corners that has a color which * contrasts with the dialog background color. Moreover, although the * Apple human interface guidelines recommend against doing so, there are * times when one wants to nest these widgets, for example placing a * GroupBox inside of a TabbedPane. To have the right contrast, each * level of nesting requires a different color. * * Previous Tk releases used the HIThemeDrawGroupBox routine to draw * GroupBoxes and TabbedPanes. This meant that the best that could be * done was to set the GroupBox to be of kind * kHIThemeGroupBoxKindPrimaryOpaque, and set its fill color to be the * system background color. If widgets inside the box were drawn with * the system background color the backgrounds would match. But this * produces a GroupBox with no contrast, the only visual clue being a * faint highlighting around the top of the GroupBox. Moreover, the * TabbedPane does not have an Opaque version, so while it is drawn * inside a contrasting rounded rectangle, the widgets inside the pane * needed to be enclosed in a frame with the system background * color. This added a visual artifact since the frame's background color * does not match the Pane's background color. That code has now been * replaced with the standalone drawing procedure macOSXDrawGroupBox, * which draws a rounded rectangle with an appropriate contrasting * background color. * * Patterned backgrounds, which are now obsolete, should be aligned with * the coordinate system of the top-level window. Apparently failing to * do this used to cause graphics anomalies when drawing into an * off-screen graphics port. The code for handling this is currently * commented out. */ static void FillElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { CGRect bounds = BoxToRect(d, b); if ([NSApp macMinorVersion] > 8) { NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace]; NSColor *bgColor; CGFloat fill[4]; BEGIN_DRAWING(d) GetBackgroundColor(dc.context, tkwin, 0, fill); bgColor = [NSColor colorWithColorSpace: deviceRGB components: fill count: 4]; CGContextSetFillColorSpace(dc.context, deviceRGB.CGColorSpace); CGContextSetFillColorWithColor(dc.context, CGCOLOR(bgColor)); CGContextFillRect(dc.context, bounds); END_DRAWING } else { ThemeBrush brush = (state & TTK_STATE_BACKGROUND) ? kThemeBrushModelessDialogBackgroundInactive : kThemeBrushModelessDialogBackgroundActive; BEGIN_DRAWING(d) ChkErr(HIThemeSetFill, brush, NULL, dc.context, HIOrientation); //QDSetPatternOrigin(PatternOrigin(tkwin, d)); CGContextFillRect(dc.context, bounds); END_DRAWING } } static void BackgroundElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { FillElementDraw(clientData, elementRecord, tkwin, d, Ttk_WinBox(tkwin), state); } static Ttk_ElementSpec FillElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TtkNullElementSize, FillElementDraw }; static Ttk_ElementSpec BackgroundElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TtkNullElementSize, BackgroundElementDraw }; /*---------------------------------------------------------------------- * +++ ToolbarBackground element -- toolbar style for frames. * * This is very similar to the normal background element, but uses a * different ThemeBrush in order to get the lighter pinstripe effect * used in toolbars. We use SetThemeBackground() rather than * ApplyThemeBackground() in order to get the right style. * * <URL: http://developer.apple.com/documentation/Carbon/Reference/ * Appearance_Manager/appearance_manager/constant_7.html#/ * /apple_ref/doc/uid/TP30000243/C005321> * */ static void ToolbarBackgroundElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { ThemeBrush brush = kThemeBrushToolbarBackground; CGRect bounds = BoxToRect(d, Ttk_WinBox(tkwin)); BEGIN_DRAWING(d) ChkErr(HIThemeSetFill, brush, NULL, dc.context, HIOrientation); //QDSetPatternOrigin(PatternOrigin(tkwin, d)); CGContextFillRect(dc.context, bounds); END_DRAWING } static Ttk_ElementSpec ToolbarBackgroundElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TtkNullElementSize, ToolbarBackgroundElementDraw }; /*---------------------------------------------------------------------- * +++ Field elements -- * * Used for the Treeview widget. This is like the BackgroundElement * except that the fieldbackground color is configureable. */ typedef struct { Tcl_Obj *backgroundObj; } FieldElement; static Ttk_ElementOptionSpec FieldElementOptions[] = { {"-fieldbackground", TK_OPTION_BORDER, Tk_Offset(FieldElement, backgroundObj), "white"}, {NULL, 0, 0, NULL} }; static void FieldElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { FieldElement *e = elementRecord; Tk_3DBorder backgroundPtr = Tk_Get3DBorderFromObj(tkwin, e->backgroundObj); XFillRectangle(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC), b.x, b.y, b.width, b.height); } static Ttk_ElementSpec FieldElementSpec = { TK_STYLE_VERSION_2, sizeof(FieldElement), FieldElementOptions, TtkNullElementSize, FieldElementDraw }; /*---------------------------------------------------------------------- * +++ Treeview headers -- * * On systems older than 10.9 The header is a kThemeListHeaderButton drawn * by HIToolbox. On newer systems those buttons do not match the Apple * buttons, so we draw them from scratch. */ static Ttk_StateTable TreeHeaderValueTable[] = { {kThemeButtonOn, TTK_STATE_ALTERNATE}, {kThemeButtonOn, TTK_STATE_SELECTED}, {kThemeButtonOff, 0} }; static Ttk_StateTable TreeHeaderAdornmentTable[] = { {kThemeAdornmentHeaderButtonSortUp, TTK_STATE_ALTERNATE | TTK_TREEVIEW_STATE_SORTARROW}, {kThemeAdornmentDefault, TTK_STATE_SELECTED | TTK_TREEVIEW_STATE_SORTARROW}, {kThemeAdornmentHeaderButtonNoSortArrow, TTK_STATE_ALTERNATE}, {kThemeAdornmentHeaderButtonNoSortArrow, TTK_STATE_SELECTED}, {kThemeAdornmentFocus, TTK_STATE_FOCUS}, {kThemeAdornmentNone, 0} }; static void TreeAreaElementSize ( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { /* * Padding is needed to get the heading text to align correctly, since the * widget expects the heading to be the same height as a row. */ if ([NSApp macMinorVersion] > 8) { paddingPtr->top = 4; } } static Ttk_ElementSpec TreeAreaElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TreeAreaElementSize, TtkNullElementDraw }; static void TreeHeaderElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { if ([NSApp macMinorVersion] > 8) { *minHeight = 24; } else { ButtonElementSize(clientData, elementRecord, tkwin, minWidth, minHeight, paddingPtr); } } static void TreeHeaderElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { ThemeButtonParams *params = clientData; CGRect bounds = BoxToRect(d, b); const HIThemeButtonDrawInfo info = { .version = 0, .state = Ttk_StateTableLookup(ThemeStateTable, state), .kind = params->kind, .value = Ttk_StateTableLookup(TreeHeaderValueTable, state), .adornment = Ttk_StateTableLookup(TreeHeaderAdornmentTable, state), }; BEGIN_DRAWING(d) if ([NSApp macMinorVersion] > 8) { /* * Compensate for the padding added in TreeHeaderElementSize, so * the larger heading will be drawn at the top of the widget. */ bounds.origin.y -= 4; if (TkMacOSXInDarkMode(tkwin)) { DrawDarkListHeader(bounds, dc.context, tkwin, state); } else { DrawListHeader(bounds, dc.context, tkwin, state); } } else { ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); } END_DRAWING } static Ttk_ElementSpec TreeHeaderElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TreeHeaderElementSize, TreeHeaderElementDraw }; /*---------------------------------------------------------------------- * +++ Disclosure triangles -- */ #define TTK_TREEVIEW_STATE_OPEN TTK_STATE_USER1 #define TTK_TREEVIEW_STATE_LEAF TTK_STATE_USER2 static Ttk_StateTable DisclosureValueTable[] = { {kThemeDisclosureDown, TTK_TREEVIEW_STATE_OPEN, 0}, {kThemeDisclosureRight, 0, 0}, }; static void DisclosureElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *minWidth, int *minHeight, Ttk_Padding *paddingPtr) { SInt32 s; ChkErr(GetThemeMetric, kThemeMetricDisclosureTriangleWidth, &s); *minWidth = s; ChkErr(GetThemeMetric, kThemeMetricDisclosureTriangleHeight, &s); *minHeight = s; } static void DisclosureElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { if (!(state & TTK_TREEVIEW_STATE_LEAF)) { int triangleState = TkMacOSXInDarkMode(tkwin) ? kThemeStateInactive : kThemeStateActive; CGRect bounds = BoxToRect(d, b); const HIThemeButtonDrawInfo info = { .version = 0, .state = triangleState, .kind = kThemeDisclosureTriangle, .value = Ttk_StateTableLookup(DisclosureValueTable, state), .adornment = kThemeAdornmentDrawIndicatorOnly, }; BEGIN_DRAWING(d) ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); END_DRAWING } } static Ttk_ElementSpec DisclosureElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, DisclosureElementSize, DisclosureElementDraw }; /*---------------------------------------------------------------------- * +++ Widget layouts -- */ TTK_BEGIN_LAYOUT_TABLE(LayoutTable) TTK_LAYOUT("Toolbar", TTK_NODE("Toolbar.background", TTK_FILL_BOTH)) TTK_LAYOUT("TButton", TTK_GROUP("Button.button", TTK_FILL_BOTH, TTK_GROUP("Button.padding", TTK_FILL_BOTH, TTK_NODE("Button.label", TTK_FILL_BOTH)))) TTK_LAYOUT("TRadiobutton", TTK_GROUP("Radiobutton.button", TTK_FILL_BOTH, TTK_GROUP("Radiobutton.padding", TTK_FILL_BOTH, TTK_NODE("Radiobutton.label", TTK_PACK_LEFT)))) TTK_LAYOUT("TCheckbutton", TTK_GROUP("Checkbutton.button", TTK_FILL_BOTH, TTK_GROUP("Checkbutton.padding", TTK_FILL_BOTH, TTK_NODE("Checkbutton.label", TTK_PACK_LEFT)))) TTK_LAYOUT("TMenubutton", TTK_GROUP("Menubutton.button", TTK_FILL_BOTH, TTK_GROUP("Menubutton.padding", TTK_FILL_BOTH, TTK_NODE("Menubutton.label", TTK_PACK_LEFT)))) TTK_LAYOUT("TCombobox", TTK_GROUP("Combobox.button", TTK_FILL_BOTH, TTK_GROUP("Combobox.padding", TTK_FILL_BOTH, TTK_NODE("Combobox.textarea", TTK_FILL_BOTH)))) /* Notebook tabs -- no focus ring */ TTK_LAYOUT("Tab", TTK_GROUP("Notebook.tab", TTK_FILL_BOTH, TTK_GROUP("Notebook.padding", TTK_EXPAND | TTK_FILL_BOTH, TTK_NODE("Notebook.label", TTK_EXPAND | TTK_FILL_BOTH)))) /* Spinbox -- buttons 2px to the right of the field. */ TTK_LAYOUT("TSpinbox", TTK_GROUP("Spinbox.buttons", TTK_PACK_RIGHT, TTK_NODE("Spinbox.uparrow", TTK_PACK_TOP | TTK_STICK_E) TTK_NODE("Spinbox.downarrow", TTK_PACK_BOTTOM | TTK_STICK_E)) TTK_GROUP("Spinbox.field", TTK_EXPAND | TTK_FILL_X, TTK_NODE("Spinbox.textarea", TTK_EXPAND | TTK_FILL_X))) /* Progress bars -- track only */ TTK_LAYOUT("TProgressbar", TTK_NODE("Progressbar.track", TTK_EXPAND | TTK_FILL_BOTH)) /* Treeview -- no border. */ TTK_LAYOUT("Treeview", TTK_GROUP("Treeview.field", TTK_FILL_BOTH, TTK_GROUP("Treeview.padding", TTK_FILL_BOTH, TTK_NODE("Treeview.treearea", TTK_FILL_BOTH)))) /* Tree heading -- no border, fixed height */ TTK_LAYOUT("Heading", TTK_NODE("Treeheading.cell", TTK_FILL_BOTH) TTK_NODE("Treeheading.image", TTK_PACK_RIGHT) TTK_NODE("Treeheading.text", TTK_PACK_TOP)) /* Tree items -- omit focus ring */ TTK_LAYOUT("Item", TTK_GROUP("Treeitem.padding", TTK_FILL_BOTH, TTK_NODE("Treeitem.indicator", TTK_PACK_LEFT) TTK_NODE("Treeitem.image", TTK_PACK_LEFT) TTK_NODE("Treeitem.text", TTK_PACK_LEFT))) /* Scrollbar Layout -- Buttons at the bottom (Snow Leopard and Lion only) */ TTK_LAYOUT("Vertical.TScrollbar", TTK_GROUP("Vertical.Scrollbar.trough", TTK_FILL_Y, TTK_NODE("Vertical.Scrollbar.thumb", TTK_PACK_TOP | TTK_EXPAND | TTK_FILL_BOTH) TTK_NODE("Vertical.Scrollbar.downarrow", TTK_PACK_BOTTOM) TTK_NODE("Vertical.Scrollbar.uparrow", TTK_PACK_BOTTOM))) TTK_LAYOUT("Horizontal.TScrollbar", TTK_GROUP("Horizontal.Scrollbar.trough", TTK_FILL_X, TTK_NODE("Horizontal.Scrollbar.thumb", TTK_PACK_LEFT | TTK_EXPAND | TTK_FILL_BOTH) TTK_NODE("Horizontal.Scrollbar.rightarrow", TTK_PACK_RIGHT) TTK_NODE("Horizontal.Scrollbar.leftarrow", TTK_PACK_RIGHT))) TTK_END_LAYOUT_TABLE /*---------------------------------------------------------------------- * +++ Initialization -- */ static int AquaTheme_Init( Tcl_Interp *interp) { Ttk_Theme themePtr = Ttk_CreateTheme(interp, "aqua", NULL); if (!themePtr) { return TCL_ERROR; } /* * Elements: */ Ttk_RegisterElementSpec(themePtr, "background", &BackgroundElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "fill", &FillElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "field", &FieldElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Toolbar.background", &ToolbarBackgroundElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Button.button", &ButtonElementSpec, &PushButtonParams); Ttk_RegisterElementSpec(themePtr, "Checkbutton.button", &ButtonElementSpec, &CheckBoxParams); Ttk_RegisterElementSpec(themePtr, "Radiobutton.button", &ButtonElementSpec, &RadioButtonParams); Ttk_RegisterElementSpec(themePtr, "Toolbutton.border", &ButtonElementSpec, &BevelButtonParams); Ttk_RegisterElementSpec(themePtr, "Menubutton.button", &ButtonElementSpec, &PopupButtonParams); Ttk_RegisterElementSpec(themePtr, "Spinbox.uparrow", &SpinButtonUpElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Spinbox.downarrow", &SpinButtonDownElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Combobox.button", &ComboboxElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Treeitem.indicator", &DisclosureElementSpec, &DisclosureParams); Ttk_RegisterElementSpec(themePtr, "Treeheading.cell", &TreeHeaderElementSpec, &ListHeaderParams); Ttk_RegisterElementSpec(themePtr, "Treeview.treearea", &TreeAreaElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Notebook.tab", &TabElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Notebook.client", &PaneElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Labelframe.border", &GroupElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Entry.field", &EntryElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Spinbox.field", &EntryElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "separator", &SeparatorElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "hseparator", &SeparatorElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "vseparator", &SeparatorElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "sizegrip", &SizegripElementSpec, 0); /* * <<NOTE-TRACKS>> * In some themes the Layouts for a progress bar has a trough element and *a * pbar element. But in our case the appearance manager draws both parts * of the progress bar, so we just have a single element called ".track". */ Ttk_RegisterElementSpec(themePtr, "Progressbar.track", &PbarElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Scale.trough", &TrackElementSpec, &ScaleData); Ttk_RegisterElementSpec(themePtr, "Scale.slider", &SliderElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Vertical.Scrollbar.trough", &TroughElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Vertical.Scrollbar.thumb", &ThumbElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Horizontal.Scrollbar.trough", &TroughElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Horizontal.Scrollbar.thumb", &ThumbElementSpec, 0); /* * If we are not in Snow Leopard or Lion the arrows won't actually be * displayed. */ Ttk_RegisterElementSpec(themePtr, "Vertical.Scrollbar.uparrow", &ArrowElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Vertical.Scrollbar.downarrow", &ArrowElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Horizontal.Scrollbar.leftarrow", &ArrowElementSpec, 0); Ttk_RegisterElementSpec(themePtr, "Horizontal.Scrollbar.rightarrow", &ArrowElementSpec, 0); /* * Layouts: */ Ttk_RegisterLayouts(themePtr, LayoutTable); Tcl_PkgProvide(interp, "ttk::theme::aqua", TTK_VERSION); return TCL_OK; } MODULE_SCOPE int Ttk_MacOSXPlatformInit( Tcl_Interp *interp) { return AquaTheme_Init(interp); } /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */ |
Changes to tests/button.test.
︙ | ︙ | |||
3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 | focus -force .top.b update event generate .top.b <space> update ; # shall not trigger error invalid command name ".top.b" } -cleanup { destroy .top.b .top } -result {} imageFinish cleanupTests return # Local variables: # mode: tcl | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 | focus -force .top.b update event generate .top.b <space> update ; # shall not trigger error invalid command name ".top.b" } -cleanup { destroy .top.b .top } -result {} test button-15.1 {Bug [5d991b822e]} { # Want this not to segfault set var INIT button .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b } {} test button-15.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT button .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} test button-15.3 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT checkbutton .b -variable var trace add variable var unset {apply {args { .b configure -variable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b } {} imageFinish cleanupTests return # Local variables: # mode: tcl |
︙ | ︙ |
Changes to tests/canvas.test.
︙ | ︙ | |||
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | {#c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0} \ {#c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0}} } -cleanup { destroy .c image delete testimage } -result 1 # cleanup imageCleanup cleanupTests return # Local Variables: # mode: tcl | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | {#c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0} \ {#c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0}} } -cleanup { destroy .c image delete testimage } -result 1 test canvas-21.1 {canvas very small arc} -setup { catch {destroy .c} canvas .c } -body { # no Inf or NaN must be generated even for very small arcs .c create arc 0 100 0 100 -height 100 -style arc -outline "" -tags arc1 set arcBox [.c bbox arc1] .c create arc 0 100 0 100 -height 100 -style arc -outline blue -tags arc2 set outlinedArcBox [.c bbox arc2] set coords [.c coords arc1] set start [.c itemcget arc1 -start] set extent [.c itemcget arc1 -extent] set width [.c itemcget arc1 -width] set height [.c itemcget arc1 -height] list $arcBox $outlinedArcBox $coords $start $extent $width $height } -result {{-1 99 1 101} {-2 98 2 102} {0.0 100.0 0.0 100.0} 0.0 0.0 1.0 0.0} destroy .c test canvas-21.1 {canvas rotate} -setup { pack [canvas .c] } -body { .c create line 50 50 50 100 100 100 .c rotate all 75 75 90 lmap c [.c coords all] {format %.2f $c} } -cleanup { destroy .c } -result {50.00 100.00 100.00 100.00 100.00 50.00} test canvas-21.2 {canvas rotate} -setup { pack [canvas .c] } -body { .c create line 50 50 50 100 100 100 .c rotate all 75 75 -10 lmap c [.c coords all] {format %.2f $c} } -cleanup { destroy .c } -result {54.72 46.04 46.04 95.28 95.28 103.96} test canvas-21.3 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate all 75 75 } -returnCodes error -cleanup { destroy .c } -result {wrong # args: should be ".c rotate tagOrId x y angle"} test canvas-21.4 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate all 75 75 123 123 } -returnCodes error -cleanup { destroy .c } -result {wrong # args: should be ".c rotate tagOrId x y angle"} test canvas-21.5 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate {!} 1 1 1 } -returnCodes error -cleanup { destroy .c } -result {missing tag in tag search expression} test canvas-21.6 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate all x 1 1 } -returnCodes error -cleanup { destroy .c } -result {bad screen distance "x"} test canvas-21.7 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate all 1 x 1 } -returnCodes error -cleanup { destroy .c } -result {bad screen distance "x"} test canvas-21.8 {canvas rotate: syntax} -setup { pack [canvas .c] } -body { .c rotate all 1 1 x } -returnCodes error -cleanup { destroy .c } -result {expected floating-point number but got "x"} test canvas-21.9 {canvas rotate: nothing to rotate} -setup { pack [canvas .c] } -body { .c rotate all 75 75 10 } -cleanup { destroy .c } -result {} test canvas-21.10 {canvas rotate: multiple things to rotate} -setup { pack [canvas .c] } -body { .c create line 50 50 50 100 -tag a .c create line 50 50 100 50 -tag b .c rotate all 75 75 45 list [lmap c [.c coords a] {format %.2f $c}] [lmap c [.c coords b] {format %.2f $c}] } -cleanup { destroy .c } -result {{39.64 75.00 75.00 110.36} {39.64 75.00 75.00 39.64}} test canvas-22.1 {canvas rotate: arc item rotation behaviour} -setup { pack [canvas .c] } -body { .c create arc 50 50 75 75 -start 45 -extent 90 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {-start -extent} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 125.00 75.00 150.00} {45.0 90.0} {52 123 73 140}} test canvas-22.2 {canvas rotate: bitmap item rotation behaviour} -setup { pack [canvas .c] } -body { .c create bitmap 50 50 -bitmap info -anchor se .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {-bitmap -anchor} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 150.00} {info se} {42 129 50 150}} test canvas-22.3 {canvas rotate: image item rotation behaviour} -setup { pack [canvas .c] image create photo dummy -width 50 -height 50 } -body { .c create image 50 50 -image dummy -anchor se .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {-image -anchor} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c image delete dummy } -result {{50.00 150.00} {dummy se} {0 100 50 150}} test canvas-22.4 {canvas rotate: line item rotation behaviour} -setup { pack [canvas .c] } -body { .c create line 50 50 75 50 50 75 75 75 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 150.00 50.00 125.00 75.00 150.00 75.00 125.00} {} {48 123 77 152}} test canvas-22.5 {canvas rotate: oval item rotation behaviour} -setup { pack [canvas .c] } -body { .c create oval 50 50 65 85 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{60.00 125.00 75.00 160.00} {} {59 124 76 161}} test canvas-22.6 {canvas rotate: polygon item rotation behaviour} -setup { pack [canvas .c] } -body { .c create polygon 50 50 75 50 50 75 75 75 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 150.00 50.00 125.00 75.00 150.00 75.00 125.00} {} {49 124 76 151}} test canvas-22.7 {canvas rotate: rectangle item rotation behaviour} -setup { pack [canvas .c] } -body { .c create rectangle 50 50 75 75 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 125.00 75.00 150.00} {} {49 124 76 151}} test canvas-22.8 {canvas rotate: text item rotation behaviour} -setup { pack [canvas .c] } -body { .c create text 50 50 -text foo -angle 45 .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {-text -angle} {.c itemcget all $o}] # [.c bbox all] # No testing of text bounding box; fonts too variable! } -cleanup { destroy .c } -result {{50.00 150.00} {foo 45.0}} test canvas-22.9 {canvas rotate: window item rotation behaviour} -setup { pack [canvas .c] } -body { .c create window 50 50 -window [frame .c.f -width 25 -height 25] \ -anchor se .c rotate all 100 100 90 list [lmap c [.c coords all] {format %.2f $c}] \ [lmap o {} {.c itemcget all $o}] \ [.c bbox all] } -cleanup { destroy .c } -result {{50.00 150.00} {} {25 125 50 150}} # cleanup imageCleanup cleanupTests return # Local Variables: # mode: tcl |
︙ | ︙ |
Changes to tests/entry.test.
︙ | ︙ | |||
3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 | destroy .e } -body { catch {entry .e -textvariable thisnsdoesntexist::myvar} result1 set result1 } -cleanup { destroy .e } -result {can't trace "thisnsdoesntexist::myvar": parent namespace doesn't exist} # Gathered comments about lacks # XXX Still need to write tests for EntryBlinkProc, EntryFocusProc, # and EntryTextVarProc. # No tests for DisplayEntry. # XXX Still need to write tests for EntryScanTo and EntrySelectTo. # No tests for EventuallyRedraw | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 | destroy .e } -body { catch {entry .e -textvariable thisnsdoesntexist::myvar} result1 set result1 } -cleanup { destroy .e } -result {can't trace "thisnsdoesntexist::myvar": parent namespace doesn't exist} test entry-25.1 {Bug [5d991b822e]} { # Want this not to segfault, or write to variable with empty name set var INIT entry .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b info exists {} } 0 test entry-25.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT entry .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} # Gathered comments about lacks # XXX Still need to write tests for EntryBlinkProc, EntryFocusProc, # and EntryTextVarProc. # No tests for DisplayEntry. # XXX Still need to write tests for EntryScanTo and EntrySelectTo. # No tests for EventuallyRedraw |
︙ | ︙ |
Changes to tests/frame.test.
︙ | ︙ | |||
643 644 645 646 647 648 649 | test frame-3.9 {TkCreateFrame procedure, -use option} -constraints { unix } -setup { deleteWindows } -body { toplevel .t -container 1 -width 300 -height 120 wm geometry .t +0+0 | < < > > > > > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | test frame-3.9 {TkCreateFrame procedure, -use option} -constraints { unix } -setup { deleteWindows } -body { toplevel .t -container 1 -width 300 -height 120 wm geometry .t +0+0 toplevel .x -width 140 -height 300 -use [winfo id .t] -bg green tkwait visibility .x list [expr {[winfo rootx .x] - [winfo rootx .t]}] \ [expr {[winfo rooty .x] - [winfo rooty .t]}] \ [winfo width .t] [winfo height .t] } -cleanup { # This call to update idletasks was added to prevent a crash that was # observed on OSX 10.12 (Sierra) only. Any change, such as using the # Development version to make debugging symbols available, adding a print # statement, or calling update idletasks here, would make the test pass # with no segfault. update idletasks deleteWindows } -result {0 0 140 300} test frame-3.10 {TkCreateFrame procedure, -use option} -constraints { unix } -setup { deleteWindows } -body { |
︙ | ︙ |
Added tests/imgSVGnano.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | # This file is a Tcl script to test out the code in tkImgSVGnano.c, which reads # and write SVG-format image files for photo widgets. The files is organized # in the standard fashion for Tcl tests. # # Copyright (c) 2018 Rene Zaumseil # All rights reserved. package require tcltest 2.2 namespace import ::tcltest::* eval tcltest::configure $argv tcltest::loadTestedCommands imageInit namespace eval svgnano { variable data set data(plus) {<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> <path fill="none" stroke="#000000" d="M0 0 h16 v16 h-16 z"/> <path fill="none" stroke="#000000" d="M8 4 v 8 M4 8 h 8"/> <circle fill="yellow" stroke="red" cx="10" cy="80" r="10" /> <ellipse fill="none" stroke="blue" stroke-width="3" cx="60" cy="60" rx="10" ry="20" /> <line x1="10" y1="90" x2="50" y2="99"/> <rect fill="none" stroke="green" x="20" y="20" width="60" height="50" rx="3" ry="3"/> <polyline fill="red" stroke="purple" points="80,10 90,20 85,40"/> <polygon fill ="yellow" points="80,80 70,85 90,90"/> </svg>} set data(bad) {<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0:w "> </svg>} test imgSVGnano-1.1 {reading simple image} -setup { catch {rename foo ""} } -body { image create photo foo -data $data(plus) list [image width foo] [image height foo] } -cleanup { rename foo "" } -result {100 100} test imgSVGnano-1.2 {simple image with options} -setup { catch {rename foo ""} } -body { image create photo foo -data $data(plus) -format {svg -dpi 100 -scale 3} list [image width foo] [image height foo] } -cleanup { rename foo "" } -result {300 300} # test on crash found by Koen Danckaert test imgSVGnano-1.3 {reformat image options} -setup { catch {rename foo ""} } -body { image create photo foo -data $data(plus) catch {foo configure -format {svg -scale}} list {} } -cleanup { rename foo "" } -result {{}} test imgSVGnano-1.4 {image options} -setup { catch {rename foo ""} } -body { image create photo foo -data $data(plus) foo configure -format {svg -scale 2} foo configure -format {svg -unit pt} foo configure -format {svg -unit mm} foo configure -format {svg -unit cm} foo configure -format {svg -unit in} foo configure -format {svg -unit px} foo configure -format {svg -dpi 600} list [image width foo] [image height foo] } -cleanup { rename foo "" } -result {100 100} test imgSVGnano-2.1 {reading a bad image} -body { image create photo foo -format svg -data $data(bad) } -returnCodes error -result {couldn't recognize image data} test imgSVGnano-2.2 {using bad option} -body { image create photo -data $data(plus) -format {svg -scale 0} } -returnCodes error -result {couldn't recognize image data} };# end of namespace svgnano namespace delete svgnano imageFinish cleanupTests return # Local Variables: # mode: tcl # fill-column: 78 # End: |
Changes to tests/listbox.test.
︙ | ︙ | |||
3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 | event generate .l <1> -x 5 -y 5 ; # <<ListboxSelect>> fires selection clear ; # <<ListboxSelect>> fires again update set res } -cleanup { destroy .l } -result {{.l 0} {{} {}}} resetGridInfo deleteWindows option clear # cleanup cleanupTests | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 | event generate .l <1> -x 5 -y 5 ; # <<ListboxSelect>> fires selection clear ; # <<ListboxSelect>> fires again update set res } -cleanup { destroy .l } -result {{.l 0} {{} {}}} test listbox-32.1 {Bug [5d991b822e]} { # Want this not to segfault, or write to variable with empty name set var INIT listbox .b -listvariable var trace add variable var unset {apply {args { .b configure -listvariable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b info exists {} } 0 test listbox-32.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT listbox .b -listvariable var trace add variable var unset {apply {args { .b configure -listvariable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} resetGridInfo deleteWindows option clear # cleanup cleanupTests |
︙ | ︙ |
Changes to tests/menu.test.
︙ | ︙ | |||
3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 | menu .m1 set foo "hello" list [.m1 add checkbutton -variable foo -onvalue hello -offvalue goodbye] \ [set foo "goodbye"] [unset foo] } -cleanup { deleteWindows } -result {{} goodbye {}} test menu-18.1 {TkActivateMenuEntry} -setup { deleteWindows } -body { menu .m1 .m1 add command -label "test" | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 | menu .m1 set foo "hello" list [.m1 add checkbutton -variable foo -onvalue hello -offvalue goodbye] \ [set foo "goodbye"] [unset foo] } -cleanup { deleteWindows } -result {{} goodbye {}} test menu-17.6 {MenuVarProc [5d991b822e]} -setup { deleteWindows } -body { # Want this not to crash menu .b set var INIT .b add checkbutton -variable var trace add variable var unset {apply {args { .b entryconfigure 1 -variable {} }}} unset var } -cleanup { deleteWindows } -result {} test menu-17.7 {MenuVarProc [5d991b822e]} -setup { deleteWindows } -body { # Want this not to duplicate traces menu .b set var INIT .b add checkbutton -variable var trace add variable var unset {apply {args { .b entryconfigure 1 -variable new }}} unset var } -cleanup { deleteWindows } -result {} test menu-18.1 {TkActivateMenuEntry} -setup { deleteWindows } -body { menu .m1 .m1 add command -label "test" |
︙ | ︙ |
Changes to tests/menubut.test.
︙ | ︙ | |||
746 747 748 749 750 751 752 753 754 755 756 757 758 759 | menubutton .mb interp hide {} .mb destroy .mb set res1 [list [winfo children .] [interp hidden]] set res2 [list {} $l] expr {$res1 eq $res2} } -result 1 deleteWindows option clear imageFinish | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 | menubutton .mb interp hide {} .mb destroy .mb set res1 [list [winfo children .] [interp hidden]] set res2 [list {} $l] expr {$res1 eq $res2} } -result 1 test menubutton-9.1 {Bug [5d991b822e]} { # Want this not to segfault, or write to variable with empty name unset -nocomplain {} set var INIT menubutton .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b info exists {} } 0 test menubutton-9.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT menubutton .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} deleteWindows option clear imageFinish |
︙ | ︙ |
Changes to tests/message.test.
︙ | ︙ | |||
465 466 467 468 469 470 471 472 473 474 | } -body { .m configure -bd 4 .m configure -bg #ffffff lindex [.m configure -bd] 4 } -cleanup { destroy .m } -result {4} cleanupTests return | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | } -body { .m configure -bd 4 .m configure -bg #ffffff lindex [.m configure -bd] 4 } -cleanup { destroy .m } -result {4} test message-4.1 {Bug [5d991b822e]} { # Want this not to segfault, or write to variable with empty name unset -nocomplain {} set var INIT message .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b info exists {} } 0 test message-4.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT message .b -textvariable var trace add variable var unset {apply {args { .b configure -textvariable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} cleanupTests return |
Added tests/pkgconfig.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | # -*- tcl -*- # Commands covered: pkgconfig # # This file contains a collection of tests for one or more of the Tk # built-in commands. Sourcing this file into Tk runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2017 Stuart Cassoff <[email protected]> # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2.2 namespace import ::tcltest::* eval tcltest::configure $argv tcltest::loadTestedCommands test pkgconfig-1.1 {query keys} nonwin { lsort [::tk::pkgconfig list] } [list \ 64bit bindir,install bindir,runtime debug demodir,install demodir,runtime \ docdir,install docdir,runtime fontsystem includedir,install includedir,runtime \ libdir,install libdir,runtime mem_debug optimized profiled \ scriptdir,install scriptdir,runtime threaded \ ] test pkgconfig-1.2 {query keys multiple times} { string compare [::tk::pkgconfig list] [::tk::pkgconfig list] } 0 test pkgconfig-1.3 {query value multiple times} { string compare \ [::tk::pkgconfig get 64bit] \ [::tk::pkgconfig get 64bit] } 0 test pkgconfig-2.0 {error: missing subcommand} { catch {::tk::pkgconfig} msg set msg } {wrong # args: should be "::tk::pkgconfig subcommand ?arg?"} test pkgconfig-2.1 {error: illegal subcommand} { catch {::tk::pkgconfig foo} msg set msg } {bad subcommand "foo": must be get or list} test pkgconfig-2.2 {error: list with arguments} { catch {::tk::pkgconfig list foo} msg set msg } {wrong # args: should be "::tk::pkgconfig list"} test pkgconfig-2.3 {error: get without arguments} { catch {::tk::pkgconfig get} msg set msg } {wrong # args: should be "::tk::pkgconfig get key"} test pkgconfig-2.4 {error: query unknown key} { catch {::tk::pkgconfig get foo} msg set msg } {key not known} test pkgconfig-2.5 {error: query with to many arguments} { catch {::tk::pkgconfig get foo bar} msg set msg } {wrong # args: should be "::tk::pkgconfig subcommand ?arg?"} # cleanup cleanupTests return |
Changes to tests/scale.test.
︙ | ︙ | |||
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 | } -body { pack [scale .s] # non-regression test for bug [55b95f578a] - shall just not crash .s configure -from -6.8e99 -to 8.8e99 } -cleanup { destroy .s } -result {} option clear # cleanup cleanupTests return | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 | } -body { pack [scale .s] # non-regression test for bug [55b95f578a] - shall just not crash .s configure -from -6.8e99 -to 8.8e99 } -cleanup { destroy .s } -result {} test scale-22.1 {Bug [5d991b822e]} { # Want this not to crash set var INIT scale .b -variable var trace add variable var unset {apply {args { .b configure -variable {} }}} pack .b bind .b <Configure> {unset var} update destroy .b } {} test scale-22.2 {Bug [5d991b822e]} { # Want this not to leak traces set var INIT scale .b -variable var trace add variable var unset {apply {args { .b configure -variable new }}} pack .b bind .b <Configure> {unset -nocomplain var} update destroy .b unset new } {} option clear # cleanup cleanupTests return |
Changes to tests/textWind.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # The statements below reset the main window; it's needed if the window # manager is mwm to make mwm forget about a previous minimum size setting. wm withdraw . wm minsize . 1 1 wm positionfrom . user wm deiconify . set bw [.t cget -borderwidth] set px [.t cget -padx] set py [.t cget -pady] set hlth [.t cget -highlightthickness] set padx [expr {$bw+$px+$hlth}] set pady [expr {$bw+$py+$hlth}] | > > > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # The statements below reset the main window; it's needed if the window # manager is mwm to make mwm forget about a previous minimum size setting. wm withdraw . wm minsize . 1 1 wm positionfrom . user wm deiconify . # This update is needed on MacOS to make sure that the window is mapped # when the tests begin. update set bw [.t cget -borderwidth] set px [.t cget -padx] set py [.t cget -pady] set hlth [.t cget -highlightthickness] set padx [expr {$bw+$px+$hlth}] set pady [expr {$bw+$py+$hlth}] |
︙ | ︙ |
Changes to tests/ttk/entry.test.
︙ | ︙ | |||
99 100 101 102 103 104 105 | .e delete 0 end .e bbox 0 } -result [list $bd $bd 0 $ch] test entry-3.2 "xview" -body { .e delete 0 end; .e insert end [string repeat "0" 40] | > > | > > > > | | > > > > > > > > > > > > > > > > > > > > > | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | .e delete 0 end .e bbox 0 } -result [list $bd $bd 0 $ch] test entry-3.2 "xview" -body { .e delete 0 end; .e insert end [string repeat "0" 40] set result [.e xview] } -result {0.0 0.5} test entry-3.3 "xview" -body { .e delete 0 end; .e insert end abcdefghijklmnopqrstuvwxyz .e xview end set result [.e index @0] } -result {7} test entry-3.4 "xview" -body { .e delete 0 end; .e insert end abcdefghijklmnopqrstuvwxyz .e xview moveto 1.0 set result [.e index @0] } -result {7} test entry-3.5 "xview" -body { .e delete 0 end; .e insert end abcdefghijklmnopqrstuvwxyz .e xview scroll 5 units set result [.e index @0] } -result {5} test entry-3.6 "xview" -body { .e delete 0 end; .e insert end [string repeat abcdefghijklmnopqrstuvwxyz 5] .e xview scroll 2 pages set result [.e index @0] } -result {40} test entry-3.last "Series 3 cleanup" -body { destroy .e } # Selection tests: |
︙ | ︙ |
Changes to tests/ttk/scrollbar.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | test scrollbar-swapout-1 "Don't use core scrollbars on OSX..." \ -constraints { coreScrollbar } -body { ttk::scrollbar .sb -command "yadda" list [winfo class .sb] [.sb cget -command] | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | test scrollbar-swapout-1 "Don't use core scrollbars on OSX..." \ -constraints { coreScrollbar } -body { ttk::scrollbar .sb -command "yadda" list [winfo class .sb] [.sb cget -command] } -result [list TScrollbar yadda] -cleanup { destroy .sb } test scrollbar-swapout-2 "... regardless of whether -style ..." \ -constraints { coreScrollbar } -body { ttk::style layout Vertical.Custom.TScrollbar \ |
︙ | ︙ |
Changes to tests/ttk/treeview.test.
︙ | ︙ | |||
466 467 468 469 470 471 472 473 474 475 476 477 478 479 | } test treeview-9.0 "scroll callback - empty tree" -body { .tv configure -yscrollcommand scrollcallback .tv delete [.tv children {}] update set ::scrolldata } -result [list 0.0 1.0] ### identify tests: # proc identify* {tv comps args} { foreach {x y} $args { foreach comp $comps { lappend result [$tv identify $comp $x $y] | > > > > > > > > > > > > | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | } test treeview-9.0 "scroll callback - empty tree" -body { .tv configure -yscrollcommand scrollcallback .tv delete [.tv children {}] update set ::scrolldata } -result [list 0.0 1.0] test treeview-9.1 "scrolling" -setup { pack [ttk::treeview .tree -show tree] -fill y for {set i 1} {$i < 100} {incr i} { .tree insert {} end -text $i } } -body { .tree yview scroll 5 units .tree identify item 2 2 } -cleanup { destroy .tree } -result {I006} ### identify tests: # proc identify* {tv comps args} { foreach {x y} $args { foreach comp $comps { lappend result [$tv identify $comp $x $y] |
︙ | ︙ | |||
631 632 633 634 635 636 637 638 639 | } -body { set item [.tv insert {} end] .tv tag remove foo $item .tv item $item -tags } -cleanup { destroy .tv } -result [list] tcltest::cleanupTests | > > > > > > > > > > > > > > > > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | } -body { set item [.tv insert {} end] .tv tag remove foo $item .tv item $item -tags } -cleanup { destroy .tv } -result [list] test treeview-368fa4561e "indicators cannot be clicked on leafs" -setup { pack [ttk::treeview .tv] .tv insert {} end -id foo -text "<-- (1) Click the blank space to my left" update } -body { foreach {x y w h} [.tv bbox foo #0] {} set res [.tv item foo -open] # using $h even for x computation is intentional here in order to simulate # a mouse click on the (invisible since we're on a leaf) indicator event generate .tv <ButtonPress-1> \ -x [expr ($x + $h / 2)] \ -y [expr ($y + $h / 2)] lappend res [.tv item foo -open] .tv insert foo end -text "sub" lappend res [.tv item foo -open] } -result {0 0 0} tcltest::cleanupTests |
Changes to unix/Makefile.in.
︙ | ︙ | |||
91 92 93 94 95 96 97 | # Directory in which to install html documentation: HTML_INSTALL_DIR = $(INSTALL_ROOT)$(HTML_DIR) # Directory in which to install the configuration file tkConfig.sh: CONFIG_INSTALL_DIR = $(INSTALL_ROOT)$(libdir) # Directory in which to install the demo files: | | | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | # Directory in which to install html documentation: HTML_INSTALL_DIR = $(INSTALL_ROOT)$(HTML_DIR) # Directory in which to install the configuration file tkConfig.sh: CONFIG_INSTALL_DIR = $(INSTALL_ROOT)$(libdir) # Directory in which to install the demo files: DEMO_INSTALL_DIR = $(INSTALL_ROOT)@DEMO_DIR@ # The directory containing the Tcl sources and headers appropriate # for this version of Tk ("srcdir" will be replaced or has already # been replaced by the configure script): TCL_GENERIC_DIR = @TCL_SRC_DIR@/generic # The directory containing the platform specific Tcl sources and headers # appropriate for this version of Tk: TCL_PLATFORM_DIR = @TCL_SRC_DIR@/unix # The directory containing the Tcl library archive file appropriate # for this version of Tk: TCL_BIN_DIR = @TCL_BIN_DIR@ # The linker flags needed to link in the Tcl library (ex: -ltcl8.2) TCL_LIB_FLAG = @TCL_LIB_FLAG@ |
︙ | ︙ | |||
306 307 308 309 310 311 312 | RANLIB = @RANLIB@ SRC_DIR = @srcdir@ TOP_DIR = $(SRC_DIR)/.. GENERIC_DIR = $(TOP_DIR)/generic TTK_DIR = $(GENERIC_DIR)/ttk UNIX_DIR = $(TOP_DIR)/unix BMAP_DIR = $(TOP_DIR)/bitmaps | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | RANLIB = @RANLIB@ SRC_DIR = @srcdir@ TOP_DIR = $(SRC_DIR)/.. GENERIC_DIR = $(TOP_DIR)/generic TTK_DIR = $(GENERIC_DIR)/ttk UNIX_DIR = $(TOP_DIR)/unix BMAP_DIR = $(TOP_DIR)/bitmaps TOOL_DIR = @TCL_SRC_DIR@/tools TEST_DIR = $(TOP_DIR)/tests MAC_OSX_DIR = $(TOP_DIR)/macosx XLIB_DIR = $(TOP_DIR)/xlib #---------------------------------------------------------------- # The information below should be usable as is. The configure # script won't modify it and you shouldn't need to modify it |
︙ | ︙ | |||
352 353 354 355 356 357 358 | tkPanedWindow.o tkScale.o tkScrollbar.o CANV_OBJS = tkCanvas.o tkCanvArc.o tkCanvBmap.o tkCanvImg.o \ tkCanvLine.o tkCanvPoly.o tkCanvPs.o tkCanvText.o \ tkCanvUtil.o tkCanvWind.o tkRectOval.o tkTrig.o IMAGE_OBJS = tkImage.o tkImgBmap.o tkImgGIF.o tkImgPNG.o tkImgPPM.o \ | | | | > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | tkPanedWindow.o tkScale.o tkScrollbar.o CANV_OBJS = tkCanvas.o tkCanvArc.o tkCanvBmap.o tkCanvImg.o \ tkCanvLine.o tkCanvPoly.o tkCanvPs.o tkCanvText.o \ tkCanvUtil.o tkCanvWind.o tkRectOval.o tkTrig.o IMAGE_OBJS = tkImage.o tkImgBmap.o tkImgGIF.o tkImgPNG.o tkImgPPM.o \ tkImgPhoto.o tkImgPhInstance.o tkImgListFormat.o tkImgSVGnano.o TEXT_OBJS = tkText.o tkTextBTree.o tkTextDisp.o tkTextImage.o tkTextIndex.o \ tkTextMark.o tkTextTag.o tkTextWind.o # either tkUnixFont.o (default) or tkUnixRFont.o (if --enable-xft) # FONT_OBJS = @UNIX_FONT_OBJS@ GENERIC_OBJS = tk3d.o tkArgv.o tkAtom.o tkBind.o tkBitmap.o tkBusy.o \ tkClipboard.o \ tkCmds.o tkColor.o tkConfig.o tkConsole.o tkCursor.o tkError.o \ tkEvent.o tkFocus.o tkFont.o tkGet.o tkGC.o tkGeometry.o tkGrab.o \ tkGrid.o tkMain.o tkObj.o tkOldConfig.o tkOption.o tkPack.o \ tkPkgConfig.o tkPlace.o tkSelect.o tkStyle.o tkUndo.o tkUtil.o \ tkVisual.o tkWindow.o TTK_OBJS = \ ttkBlink.o ttkButton.o ttkCache.o ttkClamTheme.o ttkClassicTheme.o \ ttkDefaultTheme.o ttkElements.o ttkEntry.o ttkFrame.o ttkImage.o \ ttkInit.o ttkLabel.o ttkLayout.o ttkManager.o ttkNotebook.o \ ttkPanedwindow.o ttkProgress.o ttkScale.o ttkScrollbar.o ttkScroll.o \ ttkSeparator.o ttkSquare.o ttkState.o \ |
︙ | ︙ | |||
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | $(GENERIC_DIR)/tkError.c $(GENERIC_DIR)/tkEvent.c \ $(GENERIC_DIR)/tkFocus.c $(GENERIC_DIR)/tkFont.c \ $(GENERIC_DIR)/tkGet.c $(GENERIC_DIR)/tkGC.c \ $(GENERIC_DIR)/tkGeometry.c $(GENERIC_DIR)/tkGrab.c \ $(GENERIC_DIR)/tkGrid.c $(GENERIC_DIR)/tkConsole.c \ $(GENERIC_DIR)/tkMain.c $(GENERIC_DIR)/tkOption.c \ $(GENERIC_DIR)/tkPack.c $(GENERIC_DIR)/tkPlace.c \ $(GENERIC_DIR)/tkSelect.c $(GENERIC_DIR)/tkStyle.c \ $(GENERIC_DIR)/tkUndo.c $(GENERIC_DIR)/tkUtil.c \ $(GENERIC_DIR)/tkVisual.c $(GENERIC_DIR)/tkWindow.c \ $(GENERIC_DIR)/tkButton.c $(GENERIC_DIR)/tkObj.c \ $(GENERIC_DIR)/tkEntry.c $(GENERIC_DIR)/tkFrame.c \ $(GENERIC_DIR)/tkListbox.c $(GENERIC_DIR)/tkMenu.c \ $(GENERIC_DIR)/tkMenubutton.c $(GENERIC_DIR)/tkMenuDraw.c \ $(GENERIC_DIR)/tkMessage.c $(GENERIC_DIR)/tkPanedWindow.c \ $(GENERIC_DIR)/tkScale.c $(GENERIC_DIR)/tkScrollbar.c \ $(GENERIC_DIR)/tkCanvas.c $(GENERIC_DIR)/tkCanvArc.c \ $(GENERIC_DIR)/tkCanvBmap.c $(GENERIC_DIR)/tkCanvImg.c \ $(GENERIC_DIR)/tkCanvLine.c $(GENERIC_DIR)/tkCanvPoly.c \ $(GENERIC_DIR)/tkCanvPs.c $(GENERIC_DIR)/tkCanvText.c \ $(GENERIC_DIR)/tkCanvUtil.c \ $(GENERIC_DIR)/tkCanvWind.c $(GENERIC_DIR)/tkRectOval.c \ $(GENERIC_DIR)/tkTrig.c $(GENERIC_DIR)/tkImage.c \ $(GENERIC_DIR)/tkImgBmap.c $(GENERIC_DIR)/tkImgGIF.c \ $(GENERIC_DIR)/tkImgPNG.c $(GENERIC_DIR)/tkImgPPM.c \ $(GENERIC_DIR)/tkImgPhoto.c $(GENERIC_DIR)/tkImgPhInstance.c \ $(GENERIC_DIR)/tkImgListFormat.c $(GENERIC_DIR)/tkText.c \ $(GENERIC_DIR)/tkTextBTree.c $(GENERIC_DIR)/tkTextDisp.c \ $(GENERIC_DIR)/tkTextImage.c \ $(GENERIC_DIR)/tkTextIndex.c $(GENERIC_DIR)/tkTextMark.c \ $(GENERIC_DIR)/tkTextTag.c $(GENERIC_DIR)/tkTextWind.c \ $(GENERIC_DIR)/tkOldConfig.c $(GENERIC_DIR)/tkOldTest.c \ | > > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | $(GENERIC_DIR)/tkError.c $(GENERIC_DIR)/tkEvent.c \ $(GENERIC_DIR)/tkFocus.c $(GENERIC_DIR)/tkFont.c \ $(GENERIC_DIR)/tkGet.c $(GENERIC_DIR)/tkGC.c \ $(GENERIC_DIR)/tkGeometry.c $(GENERIC_DIR)/tkGrab.c \ $(GENERIC_DIR)/tkGrid.c $(GENERIC_DIR)/tkConsole.c \ $(GENERIC_DIR)/tkMain.c $(GENERIC_DIR)/tkOption.c \ $(GENERIC_DIR)/tkPack.c $(GENERIC_DIR)/tkPlace.c \ $(GENERIC_DIR)/tkPkgConfig.c \ $(GENERIC_DIR)/tkSelect.c $(GENERIC_DIR)/tkStyle.c \ $(GENERIC_DIR)/tkUndo.c $(GENERIC_DIR)/tkUtil.c \ $(GENERIC_DIR)/tkVisual.c $(GENERIC_DIR)/tkWindow.c \ $(GENERIC_DIR)/tkButton.c $(GENERIC_DIR)/tkObj.c \ $(GENERIC_DIR)/tkEntry.c $(GENERIC_DIR)/tkFrame.c \ $(GENERIC_DIR)/tkListbox.c $(GENERIC_DIR)/tkMenu.c \ $(GENERIC_DIR)/tkMenubutton.c $(GENERIC_DIR)/tkMenuDraw.c \ $(GENERIC_DIR)/tkMessage.c $(GENERIC_DIR)/tkPanedWindow.c \ $(GENERIC_DIR)/tkScale.c $(GENERIC_DIR)/tkScrollbar.c \ $(GENERIC_DIR)/tkCanvas.c $(GENERIC_DIR)/tkCanvArc.c \ $(GENERIC_DIR)/tkCanvBmap.c $(GENERIC_DIR)/tkCanvImg.c \ $(GENERIC_DIR)/tkCanvLine.c $(GENERIC_DIR)/tkCanvPoly.c \ $(GENERIC_DIR)/tkCanvPs.c $(GENERIC_DIR)/tkCanvText.c \ $(GENERIC_DIR)/tkCanvUtil.c \ $(GENERIC_DIR)/tkCanvWind.c $(GENERIC_DIR)/tkRectOval.c \ $(GENERIC_DIR)/tkTrig.c $(GENERIC_DIR)/tkImage.c \ $(GENERIC_DIR)/tkImgBmap.c $(GENERIC_DIR)/tkImgGIF.c \ $(GENERIC_DIR)/tkImgPNG.c $(GENERIC_DIR)/tkImgPPM.c \ $(GENERIC_DIR)/tkImgSVGnano.c $(GENERIC_DIR)/tkImgSVGnano.c \ $(GENERIC_DIR)/tkImgPhoto.c $(GENERIC_DIR)/tkImgPhInstance.c \ $(GENERIC_DIR)/tkImgListFormat.c $(GENERIC_DIR)/tkText.c \ $(GENERIC_DIR)/tkTextBTree.c $(GENERIC_DIR)/tkTextDisp.c \ $(GENERIC_DIR)/tkTextImage.c \ $(GENERIC_DIR)/tkTextIndex.c $(GENERIC_DIR)/tkTextMark.c \ $(GENERIC_DIR)/tkTextTag.c $(GENERIC_DIR)/tkTextWind.c \ $(GENERIC_DIR)/tkOldConfig.c $(GENERIC_DIR)/tkOldTest.c \ |
︙ | ︙ | |||
562 563 564 565 566 567 568 | $(TTK_HDRS) $(@TK_WINDOWINGSYSTEM@_PRIVATE_HDRS) DEMOPROGS = browse hello ixset rmt rolodex square tcolor timer widget SHELL_ENV = \ @LD_LIBRARY_PATH_VAR@="`pwd`:${TCL_BIN_DIR}:$${@LD_LIBRARY_PATH_VAR@}"; \ export @LD_LIBRARY_PATH_VAR@; \ | | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | $(TTK_HDRS) $(@TK_WINDOWINGSYSTEM@_PRIVATE_HDRS) DEMOPROGS = browse hello ixset rmt rolodex square tcolor timer widget SHELL_ENV = \ @LD_LIBRARY_PATH_VAR@="`pwd`:${TCL_BIN_DIR}:$${@LD_LIBRARY_PATH_VAR@}"; \ export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY=@TCL_SRC_DIR@/library; export TCL_LIBRARY; \ TK_LIBRARY=@TK_SRC_DIR@/library; export TK_LIBRARY; all: binaries libraries doc binaries: ${LIB_FILE} ${WISH_EXE} libraries: $(TOP_DIR)/doc/man.macros: $(INSTALL_DATA) @TCL_SRC_DIR@/doc/man.macros $(TOP_DIR)/doc/man.macros doc: $(TOP_DIR)/doc/man.macros # The following target is configured by autoconf to generate either # a shared library or non-shared library for Tk. ${LIB_FILE}: ${STUB_LIB_FILE} @LIB_RSRC_FILE@ ${OBJS} rm -f $@ |
︙ | ︙ | |||
678 679 680 681 682 683 684 | demo: $(SHELL_ENV) ./${WISH_EXE} $(TOP_DIR)/library/demos/widget # This target can be used to run wish inside either gdb or insight gdb: ${WISH_EXE} @echo "set env @LD_LIBRARY_PATH_VAR@=\"`pwd`:${TCL_BIN_DIR}:$${@LD_LIBRARY_PATH_VAR@}\"" > gdb.run | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | demo: $(SHELL_ENV) ./${WISH_EXE} $(TOP_DIR)/library/demos/widget # This target can be used to run wish inside either gdb or insight gdb: ${WISH_EXE} @echo "set env @LD_LIBRARY_PATH_VAR@=\"`pwd`:${TCL_BIN_DIR}:$${@LD_LIBRARY_PATH_VAR@}\"" > gdb.run @echo "set env TCL_LIBRARY=@TCL_SRC_DIR@/library" >> gdb.run @echo "set env TK_LIBRARY=@TK_SRC_DIR@/library" >> gdb.run gdb ./${WISH_EXE} --command=gdb.run rm gdb.run VALGRINDARGS=--tool=memcheck --num-callers=8 --leak-resolution=high --leak-check=yes --show-reachable=yes -v valgrind: $(TKTEST_EXE) |
︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOldConfig.c tkOption.o: $(GENERIC_DIR)/tkOption.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOption.c tkPack.o: $(GENERIC_DIR)/tkPack.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkPack.c tkPlace.o: $(GENERIC_DIR)/tkPlace.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkPlace.c tkSelect.o: $(GENERIC_DIR)/tkSelect.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkSelect.c | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOldConfig.c tkOption.o: $(GENERIC_DIR)/tkOption.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkOption.c tkPack.o: $(GENERIC_DIR)/tkPack.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkPack.c # TIP #59, embedding of configuration information into the binary library. # # Part of Tk's configuration information are the paths where it was installed # and where it will look for its libraries (which can be different). We derive # this information from the variables which can be overridden by the user. As # every path can be configured separately we do not remember one general # prefix/exec_prefix but all the different paths individually. tkPkgConfig.o: $(GENERIC_DIR)/tkPkgConfig.c $(CC) -c $(CC_SWITCHES) \ -DCFG_INSTALL_LIBDIR="\"$(LIB_INSTALL_DIR)\"" \ -DCFG_INSTALL_BINDIR="\"$(BIN_INSTALL_DIR)\"" \ -DCFG_INSTALL_SCRDIR="\"$(SCRIPT_INSTALL_DIR)\"" \ -DCFG_INSTALL_INCDIR="\"$(INCLUDE_INSTALL_DIR)\"" \ -DCFG_INSTALL_DOCDIR="\"$(MAN_INSTALL_DIR)\"" \ -DCFG_INSTALL_DEMODIR="\"$(DEMO_INSTALL_DIR)\"" \ \ -DCFG_RUNTIME_LIBDIR="\"$(libdir)\"" \ -DCFG_RUNTIME_BINDIR="\"$(bindir)\"" \ -DCFG_RUNTIME_SCRDIR="\"$(TK_LIBRARY)\"" \ -DCFG_RUNTIME_INCDIR="\"$(includedir)\"" \ -DCFG_RUNTIME_DOCDIR="\"$(mandir)\"" \ -DCFG_RUNTIME_DEMODIR="\"$(DEMO_INSTALL_DIR)\"" \ \ $(GENERIC_DIR)/tkPkgConfig.c tkPlace.o: $(GENERIC_DIR)/tkPlace.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkPlace.c tkSelect.o: $(GENERIC_DIR)/tkSelect.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkSelect.c |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | tkImgPNG.o: $(GENERIC_DIR)/tkImgPNG.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPNG.c tkImgPPM.o: $(GENERIC_DIR)/tkImgPPM.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPPM.c tkImgPhoto.o: $(GENERIC_DIR)/tkImgPhoto.c $(GENERIC_DIR)/tkImgPhoto.h $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhoto.c tkImgPhInstance.o: $(GENERIC_DIR)/tkImgPhInstance.c $(GENERIC_DIR)/tkImgPhoto.h $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhInstance.c tkOldTest.o: $(GENERIC_DIR)/tkOldTest.c | > > > | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 | tkImgPNG.o: $(GENERIC_DIR)/tkImgPNG.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPNG.c tkImgPPM.o: $(GENERIC_DIR)/tkImgPPM.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPPM.c tkImgSVGnano.o: $(GENERIC_DIR)/tkImgSVGnano.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgSVGnano.c tkImgPhoto.o: $(GENERIC_DIR)/tkImgPhoto.c $(GENERIC_DIR)/tkImgPhoto.h $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhoto.c tkImgPhInstance.o: $(GENERIC_DIR)/tkImgPhInstance.c $(GENERIC_DIR)/tkImgPhoto.h $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhInstance.c tkOldTest.o: $(GENERIC_DIR)/tkOldTest.c |
︙ | ︙ | |||
1530 1531 1532 1533 1534 1535 1536 | # to put the distribution. DISTDIR must be an absolute path name. # DISTROOT = /tmp/dist DISTNAME = tk${VERSION}${PATCH_LEVEL} ZIPNAME = tk${MAJOR_VERSION}${MINOR_VERSION}${PATCH_LEVEL}-src.zip DISTDIR = $(DISTROOT)/$(DISTNAME) | | | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | # to put the distribution. DISTDIR must be an absolute path name. # DISTROOT = /tmp/dist DISTNAME = tk${VERSION}${PATCH_LEVEL} ZIPNAME = tk${MAJOR_VERSION}${MINOR_VERSION}${PATCH_LEVEL}-src.zip DISTDIR = $(DISTROOT)/$(DISTNAME) TCLDIR = @TCL_SRC_DIR@ DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644 DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755 $(UNIX_DIR)/configure: $(UNIX_DIR)/configure.ac $(UNIX_DIR)/tcl.m4 \ $(UNIX_DIR)/aclocal.m4 cd $(UNIX_DIR); autoconf $(MAC_OSX_DIR)/configure: $(MAC_OSX_DIR)/configure.ac $(UNIX_DIR)/configure |
︙ | ︙ | |||
1687 1688 1689 1690 1691 1692 1693 | @EXTRA_BUILD_HTML@ BUILD_HTML = \ @if test -f "$(BUILD_TCLSH)"; then \ $(SHELL_ENV) TCLSH="$(BUILD_TCLSH)"; else \ TCLSH="$(TCL_EXE)"; fi ;\ "$${TCLSH}" $(TOOL_DIR)/tcltk-man2html.tcl --htmldir="$(HTML_INSTALL_DIR)" \ | | | 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 | @EXTRA_BUILD_HTML@ BUILD_HTML = \ @if test -f "$(BUILD_TCLSH)"; then \ $(SHELL_ENV) TCLSH="$(BUILD_TCLSH)"; else \ TCLSH="$(TCL_EXE)"; fi ;\ "$${TCLSH}" $(TOOL_DIR)/tcltk-man2html.tcl --htmldir="$(HTML_INSTALL_DIR)" \ --srcdir=$(TOP_DIR)/.. $(BUILD_HTML_FLAGS) # # The list of all the targets that do not correspond to real files. This stops # 'make' from getting confused when someone makes an error in a rule. # .PHONY: all binaries libraries objs doc html html-tcl html-tk test runtest |
︙ | ︙ |
Changes to unix/configure.
︙ | ︙ | |||
657 658 659 660 661 662 663 664 665 666 667 668 669 670 | TK_LIB_FLAG TK_LIB_FILE TK_YEAR TK_PATCH_LEVEL TK_MINOR_VERSION TK_MAJOR_VERSION TK_VERSION UNIX_FONT_OBJS XFT_LIBS XFT_CFLAGS XMKMF LDFLAGS_DEFAULT CFLAGS_DEFAULT INSTALL_STUB_LIB | > > | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | TK_LIB_FLAG TK_LIB_FILE TK_YEAR TK_PATCH_LEVEL TK_MINOR_VERSION TK_MAJOR_VERSION TK_VERSION TK_DEMO_DIR DEMO_DIR UNIX_FONT_OBJS XFT_LIBS XFT_CFLAGS XMKMF LDFLAGS_DEFAULT CFLAGS_DEFAULT INSTALL_STUB_LIB |
︙ | ︙ | |||
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MAN_FLAGS TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION | > > < < < < < > | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MAN_FLAGS BUILD_TCLSH TCLSH_PROG TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir |
︙ | ︙ | |||
764 765 766 767 768 769 770 771 772 773 774 775 776 777 | ac_subst_files='' ac_user_opts=' enable_option_checking with_tcl enable_man_symlinks enable_man_compression enable_man_suffix enable_shared enable_64bit enable_64bit_vis enable_rpath enable_corefoundation enable_load enable_symbols | > | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | ac_subst_files='' ac_user_opts=' enable_option_checking with_tcl enable_man_symlinks enable_man_compression enable_man_suffix with_encoding enable_shared enable_64bit enable_64bit_vis enable_rpath enable_corefoundation enable_load enable_symbols |
︙ | ︙ | |||
825 826 827 828 829 830 831 832 833 834 835 836 837 838 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' | > | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' |
︙ | ︙ | |||
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; | > > > > > > > > > | 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; |
︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; |
︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] | > | 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] |
︙ | ︙ | |||
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 | (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-x use the X Window System Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> | > > | 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 | (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-encoding encoding for configuration values (default: iso8859-1) --with-x use the X Window System Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> |
︙ | ︙ | |||
2286 2287 2288 2289 2290 2291 2292 | TK_PATCH_LEVEL="a2" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" #-------------------------------------------------------------------- # Find and load the tclConfig.sh file #-------------------------------------------------------------------- | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 | TK_PATCH_LEVEL="a2" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" #-------------------------------------------------------------------- # Find and load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # |
︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 | # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 | # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" |
︙ | ︙ | |||
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 | Found config for Tcl ${TCL_VERSION}" "$LINENO" 5 fi if test "${TCL_MINOR_VERSION}" -lt 6 ; then as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6+ Found config for Tcl ${TCL_VERSION}" "$LINENO" 5 fi fi #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 | Found config for Tcl ${TCL_VERSION}" "$LINENO" 5 fi if test "${TCL_MINOR_VERSION}" -lt 6 ; then as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6+ Found config for Tcl ${TCL_VERSION}" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 $as_echo_n "checking for tclsh... " >&6; } if ${ac_cv_path_tclsh+:} false; then : $as_echo_n "(cached) " >&6 else search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/tclsh[8-9]* 2> /dev/null` \ `ls -r $dir/tclsh* 2> /dev/null` ; do if test x"$ac_cv_path_tclsh" = x ; then if test -f "$j" ; then ac_cv_path_tclsh=$j break fi fi done done fi if test -f "$ac_cv_path_tclsh" ; then TCLSH_PROG="$ac_cv_path_tclsh" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_PROG" >&5 $as_echo "$TCLSH_PROG" >&6; } else # It is not an error if an installed version of Tcl can't be located. TCLSH_PROG="" { $as_echo "$as_me:${as_lineno-$LINENO}: result: No tclsh found on PATH" >&5 $as_echo "No tclsh found on PATH" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh in Tcl build directory" >&5 $as_echo_n "checking for tclsh in Tcl build directory... " >&6; } BUILD_TCLSH="${TCL_BIN_DIR}"/tclsh { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_TCLSH" >&5 $as_echo "$BUILD_TCLSH" >&6; } #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then |
︙ | ︙ | |||
4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 $as_echo "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 $as_echo_n "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; tcl_ok=$enableval else | > > > > > > > > > > > > > > > > > > > > > > > > > | 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 $as_echo "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #------------------------------------------------------------------------ # Embedded configuration information, encoding to use for the values, TIP #59 #------------------------------------------------------------------------ # Check whether --with-encoding was given. if test "${with_encoding+set}" = set; then : withval=$with_encoding; with_tcencoding=${withval} fi if test x"${with_tcencoding}" != x ; then cat >>confdefs.h <<_ACEOF #define TCL_CFGVAL_ENCODING "${with_tcencoding}" _ACEOF else $as_echo "#define TCL_CFGVAL_ENCODING \"iso8859-1\"" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 $as_echo_n "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; tcl_ok=$enableval else |
︙ | ︙ | |||
5364 5365 5366 5367 5368 5369 5370 | SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" | < < < < < < | 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 | SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" LDFLAGS="$LDFLAGS -headerpad_max_install_names" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 $as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; } if ${tcl_cv_ld_search_paths_first+:} false; then : $as_echo_n "(cached) " >&6 else |
︙ | ︙ | |||
8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 | TK_BUILD_STUB_LIB_SPEC="-L`pwd | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_SPEC="-L${TK_STUB_LIB_DIR} ${TK_STUB_LIB_FLAG}" TK_BUILD_STUB_LIB_PATH="`pwd`/${TK_STUB_LIB_FILE}" TK_STUB_LIB_PATH="${TK_STUB_LIB_DIR}/${TK_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TK_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # tkConfig.sh refers to this by a different name #------------------------------------------------------------------------ TK_SHARED_BUILD=${SHARED_BUILD} | > > > > > > > > > > > > | 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 | TK_BUILD_STUB_LIB_SPEC="-L`pwd | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_SPEC="-L${TK_STUB_LIB_DIR} ${TK_STUB_LIB_FLAG}" TK_BUILD_STUB_LIB_PATH="`pwd`/${TK_STUB_LIB_FILE}" TK_STUB_LIB_PATH="${TK_STUB_LIB_DIR}/${TK_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TK_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # Demo dir #------------------------------------------------------------------------ if test x"${DEMO_DIR}" = x; then : DEMO_DIR='$(TK_LIBRARY)/demos' fi eval "TK_DEMO_DIR=\"`echo ${DEMO_DIR} | tr '()' '{}'`\"" eval "TK_DEMO_DIR=\"`echo ${TK_DEMO_DIR} | tr '()' '{}'`\"" #------------------------------------------------------------------------ # tkConfig.sh refers to this by a different name #------------------------------------------------------------------------ TK_SHARED_BUILD=${SHARED_BUILD} |
︙ | ︙ |
Changes to unix/configure.ac.
︙ | ︙ | |||
28 29 30 31 32 33 34 | TK_PATCH_LEVEL="a2" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" #-------------------------------------------------------------------- # Find and load the tclConfig.sh file #-------------------------------------------------------------------- | < < > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | TK_PATCH_LEVEL="a2" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" #-------------------------------------------------------------------- # Find and load the tclConfig.sh file #-------------------------------------------------------------------- SC_PATH_TCLCONFIG SC_LOAD_TCLCONFIG if test "${TCL_MAJOR_VERSION}" -lt 9 ; then if test "${TCL_MAJOR_VERSION}" -ne 8 ; then AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6+ Found config for Tcl ${TCL_VERSION}]) fi if test "${TCL_MINOR_VERSION}" -lt 6 ; then AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6+ Found config for Tcl ${TCL_VERSION}]) fi fi SC_PROG_TCLSH SC_BUILD_TCLSH #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then prefix="$TCL_PREFIX" |
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 | hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi SC_ENABLE_SHARED #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. | > > > > > > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #------------------------------------------------------------------------ # Embedded configuration information, encoding to use for the values, TIP #59 #------------------------------------------------------------------------ SC_TCL_CFG_ENCODING SC_ENABLE_SHARED #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. |
︙ | ︙ | |||
767 768 769 770 771 772 773 774 775 776 777 778 779 780 | TK_BUILD_STUB_LIB_SPEC="-L`pwd | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_SPEC="-L${TK_STUB_LIB_DIR} ${TK_STUB_LIB_FLAG}" TK_BUILD_STUB_LIB_PATH="`pwd`/${TK_STUB_LIB_FILE}" TK_STUB_LIB_PATH="${TK_STUB_LIB_DIR}/${TK_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TK_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # tkConfig.sh refers to this by a different name #------------------------------------------------------------------------ TK_SHARED_BUILD=${SHARED_BUILD} | > > > > > > > > > > | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | TK_BUILD_STUB_LIB_SPEC="-L`pwd | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_SPEC="-L${TK_STUB_LIB_DIR} ${TK_STUB_LIB_FLAG}" TK_BUILD_STUB_LIB_PATH="`pwd`/${TK_STUB_LIB_FILE}" TK_STUB_LIB_PATH="${TK_STUB_LIB_DIR}/${TK_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TK_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # Demo dir #------------------------------------------------------------------------ AS_IF([test x"${DEMO_DIR}" = x], [DEMO_DIR='$(TK_LIBRARY)/demos']) eval "TK_DEMO_DIR=\"`echo ${DEMO_DIR} | tr '()' '{}'`\"" eval "TK_DEMO_DIR=\"`echo ${TK_DEMO_DIR} | tr '()' '{}'`\"" AC_SUBST(DEMO_DIR) AC_SUBST(TK_DEMO_DIR) #------------------------------------------------------------------------ # tkConfig.sh refers to this by a different name #------------------------------------------------------------------------ TK_SHARED_BUILD=${SHARED_BUILD} |
︙ | ︙ |
Changes to unix/tcl.m4.
︙ | ︙ | |||
332 333 334 335 336 337 338 | # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" | < < | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) |
︙ | ︙ | |||
430 431 432 433 434 435 436 | AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) ]) | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) ]) #------------------------------------------------------------------------ # SC_PROG_TCLSH # Locate a tclsh shell installed on the system path. This macro # will only find a Tcl shell that already exists on the system. # It will not find a Tcl shell in the Tcl build directory or # a Tcl shell that has been installed from the Tcl build directory. # If a Tcl shell can't be located on the PATH, then TCLSH_PROG will |
︙ | ︙ | |||
599 600 601 602 603 604 605 | done ]) if test -f "$ac_cv_path_tclsh" ; then TCLSH_PROG="$ac_cv_path_tclsh" AC_MSG_RESULT([$TCLSH_PROG]) else | > > | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | done ]) if test -f "$ac_cv_path_tclsh" ; then TCLSH_PROG="$ac_cv_path_tclsh" AC_MSG_RESULT([$TCLSH_PROG]) else # It is not an error if an installed version of Tcl can't be located. TCLSH_PROG="" AC_MSG_RESULT([No tclsh found on PATH]) fi AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # SC_BUILD_TCLSH # Determine the fully qualified path name of the tclsh executable |
︙ | ︙ | |||
1583 1584 1585 1586 1587 1588 1589 | LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" | < < < < | 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 | LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) |
︙ | ︙ | |||
3138 3139 3140 3141 3142 3143 3144 | done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" | | | | 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 | done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" ZIP_PROG_VFSSEARCH="*" AC_MSG_RESULT([Found INFO Zip in environment]) # Use standard arguments for zip else # It is not an error if an installed version of Zip can't be located. # We can use the locally distributed minizip instead ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" ZIP_PROG_OPTIONS="-o -r" ZIP_PROG_VFSSEARCH="*" ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" AC_MSG_RESULT([No zip found on PATH. Building minizip]) fi AC_SUBST(ZIP_PROG) AC_SUBST(ZIP_PROG_OPTIONS) AC_SUBST(ZIP_PROG_VFSSEARCH) AC_SUBST(ZIP_INSTALL_OBJS) ]) # Local Variables: # mode: autoconf # End: |
Changes to unix/tk.pc.in.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # tk pkg-config source file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: The Tk Toolkit Description: Tk is a cross-platform graphical user interface toolkit, the standard GUI not only for Tcl, but for many other dynamic languages as well. URL: http://www.tcl.tk/ Version: @TK_VERSION@@TK_PATCH_LEVEL@ Requires: tcl >= 8.6 Libs: -L${libdir} @TK_LIB_FLAG@ @TK_STUB_LIB_FLAG@ | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # tk pkg-config source file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ demodir=@TK_DEMO_DIR@ Name: The Tk Toolkit Description: Tk is a cross-platform graphical user interface toolkit, the standard GUI not only for Tcl, but for many other dynamic languages as well. URL: http://www.tcl.tk/ Version: @TK_VERSION@@TK_PATCH_LEVEL@ Requires: tcl >= 8.6 Libs: -L${libdir} @TK_LIB_FLAG@ @TK_STUB_LIB_FLAG@ |
︙ | ︙ |
Changes to unix/tkConfig.h.in.
︙ | ︙ | |||
131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Is this a static build? */ #undef STATIC_BUILD /* Is this a 64-bit build? */ #undef TCL_CFG_DO64BIT /* Is this an optimized build? */ #undef TCL_CFG_OPTIMIZED | > > > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Is this a static build? */ #undef STATIC_BUILD /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* What encoding should be used for embedded configuration info? */ #undef TCL_CFGVAL_ENCODING /* Is this a 64-bit build? */ #undef TCL_CFG_DO64BIT /* Is this an optimized build? */ #undef TCL_CFG_OPTIMIZED |
︙ | ︙ |
Changes to unix/tkConfig.sh.in.
︙ | ︙ | |||
91 92 93 94 95 96 97 | TK_STUB_LIB_SPEC='@TK_STUB_LIB_SPEC@' # Path to the Tk stub library in the build directory. TK_BUILD_STUB_LIB_PATH='@TK_BUILD_STUB_LIB_PATH@' # Path to the Tk stub library in the install directory. TK_STUB_LIB_PATH='@TK_STUB_LIB_PATH@' | > > > | 91 92 93 94 95 96 97 98 99 100 | TK_STUB_LIB_SPEC='@TK_STUB_LIB_SPEC@' # Path to the Tk stub library in the build directory. TK_BUILD_STUB_LIB_PATH='@TK_BUILD_STUB_LIB_PATH@' # Path to the Tk stub library in the install directory. TK_STUB_LIB_PATH='@TK_STUB_LIB_PATH@' # Top-level directory in which Tk's demo files are installed. TK_DEMO_DIR='@TK_DEMO_DIR@' |
Changes to unix/tkUnixDefault.h.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #define BLACK "#000000" #define WHITE "#ffffff" #define NORMAL_BG "#d9d9d9" #define ACTIVE_BG "#ececec" #define SELECT_BG "#c3c3c3" #define TROUGH "#b3b3b3" | | < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #define BLACK "#000000" #define WHITE "#ffffff" #define NORMAL_BG "#d9d9d9" #define ACTIVE_BG "#ececec" #define SELECT_BG "#c3c3c3" #define TROUGH "#b3b3b3" #define INDICATOR WHITE #define DISABLED "#a3a3a3" /* * Defaults for labels, buttons, checkbuttons, and radiobuttons: */ #define DEF_BUTTON_ANCHOR "center" |
︙ | ︙ | |||
75 76 77 78 79 80 81 | #define DEF_LABCHKRAD_PADX "1" #define DEF_BUTTON_PADY "1m" #define DEF_LABCHKRAD_PADY "1" #define DEF_BUTTON_RELIEF "raised" #define DEF_LABCHKRAD_RELIEF "flat" #define DEF_BUTTON_REPEAT_DELAY "0" #define DEF_BUTTON_REPEAT_INTERVAL "0" | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #define DEF_LABCHKRAD_PADX "1" #define DEF_BUTTON_PADY "1m" #define DEF_LABCHKRAD_PADY "1" #define DEF_BUTTON_RELIEF "raised" #define DEF_LABCHKRAD_RELIEF "flat" #define DEF_BUTTON_REPEAT_DELAY "0" #define DEF_BUTTON_REPEAT_INTERVAL "0" #define DEF_BUTTON_SELECT_COLOR INDICATOR #define DEF_BUTTON_SELECT_MONO BLACK #define DEF_BUTTON_SELECT_IMAGE NULL #define DEF_BUTTON_STATE "normal" #define DEF_LABEL_TAKE_FOCUS "0" #define DEF_BUTTON_TAKE_FOCUS NULL #define DEF_BUTTON_TEXT "" #define DEF_BUTTON_TEXT_VARIABLE "" |
︙ | ︙ | |||
285 286 287 288 289 290 291 | #define DEF_MENU_CURSOR "arrow" #define DEF_MENU_DISABLED_FG_COLOR DISABLED #define DEF_MENU_DISABLED_FG_MONO "" #define DEF_MENU_FONT "TkMenuFont" #define DEF_MENU_FG BLACK #define DEF_MENU_POST_COMMAND "" #define DEF_MENU_RELIEF "raised" | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | #define DEF_MENU_CURSOR "arrow" #define DEF_MENU_DISABLED_FG_COLOR DISABLED #define DEF_MENU_DISABLED_FG_MONO "" #define DEF_MENU_FONT "TkMenuFont" #define DEF_MENU_FG BLACK #define DEF_MENU_POST_COMMAND "" #define DEF_MENU_RELIEF "raised" #define DEF_MENU_SELECT_COLOR BLACK #define DEF_MENU_SELECT_MONO BLACK #define DEF_MENU_TAKE_FOCUS "0" #define DEF_MENU_TEAROFF "0" #define DEF_MENU_TEAROFF_CMD NULL #define DEF_MENU_TITLE "" #define DEF_MENU_TYPE "normal" |
︙ | ︙ |
Changes to unix/tkUnixRFont.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | typedef struct ThreadSpecificData { Region clipRegion; /* The clipping region, or None. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* | > > > > > | > | < > > | | | < | | > > > < < < < < < | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | typedef struct ThreadSpecificData { Region clipRegion; /* The clipping region, or None. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* *------------------------------------------------------------------------- * * TkpFontPkgInit -- * * This procedure is called when an application is created. It * initializes all the structures that are used by the * platform-dependant code on a per application basis. * Note that this is called before TkpInit() ! * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------- */ void TkpFontPkgInit( TkMainInfo *mainPtr) /* The application being created. */ { } static XftFont * GetFont( UnixFtFont *fontPtr, FcChar32 ucs4, double angle) |
︙ | ︙ |
Changes to win/Makefile.in.
︙ | ︙ | |||
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | tkGrid.$(OBJEXT) \ tkImage.$(OBJEXT) \ tkImgBmap.$(OBJEXT) \ tkImgListFormat.$(OBJEXT) \ tkImgGIF.$(OBJEXT) \ tkImgPNG.$(OBJEXT) \ tkImgPPM.$(OBJEXT) \ tkImgPhoto.$(OBJEXT) \ tkImgPhInstance.$(OBJEXT) \ tkImgUtil.$(OBJEXT) \ tkListbox.$(OBJEXT) \ tkMacWinMenu.$(OBJEXT) \ tkMain.$(OBJEXT) \ tkMain2.$(OBJEXT) \ tkMenu.$(OBJEXT) \ tkMenubutton.$(OBJEXT) \ tkMenuDraw.$(OBJEXT) \ tkMessage.$(OBJEXT) \ tkPanedWindow.$(OBJEXT) \ tkObj.$(OBJEXT) \ tkOldConfig.$(OBJEXT) \ tkOption.$(OBJEXT) \ tkPack.$(OBJEXT) \ tkPlace.$(OBJEXT) \ tkPointer.$(OBJEXT) \ tkRectOval.$(OBJEXT) \ tkScale.$(OBJEXT) \ tkScrollbar.$(OBJEXT) \ tkSelect.$(OBJEXT) \ tkStyle.$(OBJEXT) \ | > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | tkGrid.$(OBJEXT) \ tkImage.$(OBJEXT) \ tkImgBmap.$(OBJEXT) \ tkImgListFormat.$(OBJEXT) \ tkImgGIF.$(OBJEXT) \ tkImgPNG.$(OBJEXT) \ tkImgPPM.$(OBJEXT) \ tkImgSVGnano.$(OBJEXT) \ tkImgPhoto.$(OBJEXT) \ tkImgPhInstance.$(OBJEXT) \ tkImgUtil.$(OBJEXT) \ tkListbox.$(OBJEXT) \ tkMacWinMenu.$(OBJEXT) \ tkMain.$(OBJEXT) \ tkMain2.$(OBJEXT) \ tkMenu.$(OBJEXT) \ tkMenubutton.$(OBJEXT) \ tkMenuDraw.$(OBJEXT) \ tkMessage.$(OBJEXT) \ tkPanedWindow.$(OBJEXT) \ tkObj.$(OBJEXT) \ tkOldConfig.$(OBJEXT) \ tkOption.$(OBJEXT) \ tkPack.$(OBJEXT) \ tkPkgConfig.$(OBJEXT) \ tkPlace.$(OBJEXT) \ tkPointer.$(OBJEXT) \ tkRectOval.$(OBJEXT) \ tkScale.$(OBJEXT) \ tkScrollbar.$(OBJEXT) \ tkSelect.$(OBJEXT) \ tkStyle.$(OBJEXT) \ |
︙ | ︙ |
Changes to win/configure.
︙ | ︙ | |||
736 737 738 739 740 741 742 743 744 745 746 747 748 749 | pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir | > | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir |
︙ | ︙ | |||
812 813 814 815 816 817 818 819 820 821 822 823 824 825 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' | > | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; | > > > > > > > > > | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ | | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; |
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] | > | 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] |
︙ | ︙ | |||
4309 4310 4311 4312 4313 4314 4315 | LIBFLAGSUFFIX="\${DBGX}" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" | | | 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 | LIBFLAGSUFFIX="\${DBGX}" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" CFLAGS_WARNING="-Wall -Wwrite-strings -Wsign-compare -Wdeclaration-after-statement -Wpointer-arith" LDFLAGS_DEBUG= LDFLAGS_OPTIMIZE= # Specify the CC output file names based on the target name CC_OBJNAME="-o \$@" CC_EXENAME="-o \$@" |
︙ | ︙ |
Changes to win/makefile.vc.
︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | $(TMP_DIR)\tkGrid.obj \ $(TMP_DIR)\tkImage.obj \ $(TMP_DIR)\tkImgBmap.obj \ $(TMP_DIR)\tkImgListFormat.obj \ $(TMP_DIR)\tkImgGIF.obj \ $(TMP_DIR)\tkImgPNG.obj \ $(TMP_DIR)\tkImgPPM.obj \ $(TMP_DIR)\tkImgPhoto.obj \ $(TMP_DIR)\tkImgPhInstance.obj \ $(TMP_DIR)\tkImgUtil.obj \ $(TMP_DIR)\tkListbox.obj \ $(TMP_DIR)\tkMacWinMenu.obj \ $(TMP_DIR)\tkMain.obj \ $(TMP_DIR)\tkMain2.obj \ $(TMP_DIR)\tkMenu.obj \ $(TMP_DIR)\tkMenubutton.obj \ $(TMP_DIR)\tkMenuDraw.obj \ $(TMP_DIR)\tkMessage.obj \ $(TMP_DIR)\tkPanedWindow.obj \ $(TMP_DIR)\tkObj.obj \ $(TMP_DIR)\tkOldConfig.obj \ $(TMP_DIR)\tkOption.obj \ $(TMP_DIR)\tkPack.obj \ $(TMP_DIR)\tkPlace.obj \ $(TMP_DIR)\tkPointer.obj \ $(TMP_DIR)\tkRectOval.obj \ $(TMP_DIR)\tkScale.obj \ $(TMP_DIR)\tkScrollbar.obj \ $(TMP_DIR)\tkSelect.obj \ $(TMP_DIR)\tkStyle.obj \ | > > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | $(TMP_DIR)\tkGrid.obj \ $(TMP_DIR)\tkImage.obj \ $(TMP_DIR)\tkImgBmap.obj \ $(TMP_DIR)\tkImgListFormat.obj \ $(TMP_DIR)\tkImgGIF.obj \ $(TMP_DIR)\tkImgPNG.obj \ $(TMP_DIR)\tkImgPPM.obj \ $(TMP_DIR)\tkImgSVGnano.obj \ $(TMP_DIR)\tkImgPhoto.obj \ $(TMP_DIR)\tkImgPhInstance.obj \ $(TMP_DIR)\tkImgUtil.obj \ $(TMP_DIR)\tkListbox.obj \ $(TMP_DIR)\tkMacWinMenu.obj \ $(TMP_DIR)\tkMain.obj \ $(TMP_DIR)\tkMain2.obj \ $(TMP_DIR)\tkMenu.obj \ $(TMP_DIR)\tkMenubutton.obj \ $(TMP_DIR)\tkMenuDraw.obj \ $(TMP_DIR)\tkMessage.obj \ $(TMP_DIR)\tkPanedWindow.obj \ $(TMP_DIR)\tkObj.obj \ $(TMP_DIR)\tkOldConfig.obj \ $(TMP_DIR)\tkOption.obj \ $(TMP_DIR)\tkPack.obj \ $(TMP_DIR)\tkPkgConfig.obj \ $(TMP_DIR)\tkPlace.obj \ $(TMP_DIR)\tkPointer.obj \ $(TMP_DIR)\tkRectOval.obj \ $(TMP_DIR)\tkScale.obj \ $(TMP_DIR)\tkScrollbar.obj \ $(TMP_DIR)\tkSelect.obj \ $(TMP_DIR)\tkStyle.obj \ |
︙ | ︙ |
Changes to win/rules.vc.
︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 | !endif !if "$(MACHINE)" != "$(ARCH)" !error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). !endif !else MACHINE=$(ARCH) !endif #------------------------------------------------------------ # Figure out the *host* architecture by reading the registry !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else | > > > > > > > > > > > > > > > | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | !endif !if "$(MACHINE)" != "$(ARCH)" !error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). !endif !else MACHINE=$(ARCH) !endif #--------------------------------------------------------------- # The PLATFORM_IDENTIFY macro matches the values returned by # the Tcl platform::identify command !if "$(MACHINE)" == "AMD64" PLATFORM_IDENTIFY = win32-x86_64 !else PLATFORM_IDENTIFY = win32-ix86 !endif # The MULTIPLATFORM macro controls whether binary extensions are installed # in platform-specific directories. Intended to be set/used by extensions. !ifndef MULTIPLATFORM_INSTALL MULTIPLATFORM_INSTALL = 0 !endif #------------------------------------------------------------ # Figure out the *host* architecture by reading the registry !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else |
︙ | ︙ | |||
726 727 728 729 730 731 732 733 734 735 736 737 738 739 | !if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif | > > | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | !if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif # Yes, it's weird that the "symbols" option controls DEBUG and # the "pdbs" option controls SYMBOLS. That's historical. !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | !endif DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include !endif | > > > > > | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | !endif DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) !if $(MULTIPLATFORM_INSTALL) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) !else LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) !endif DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include !endif |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 | !ifndef DEFAULT_BUILD_TARGET DEFAULT_BUILD_TARGET = $(PROJECT) !endif default-target: $(DEFAULT_BUILD_TARGET) default-pkgindex: @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ [list load [file join $$dir $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl default-pkgindex-tea: @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl @PACKAGE_VERSION@ $(DOTVERSION) @PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) @PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) @PKG_LIB_FILE@ $(PRJLIBNAME) << | > > > > > > | > | > > > > > > > | | | > | > > > > > > > | 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 | !ifndef DEFAULT_BUILD_TARGET DEFAULT_BUILD_TARGET = $(PROJECT) !endif default-target: $(DEFAULT_BUILD_TARGET) !if $(MULTIPLATFORM_INSTALL) default-pkgindex: @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl !else default-pkgindex: @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ [list load [file join $$dir $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl !endif default-pkgindex-tea: @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl @PACKAGE_VERSION@ $(DOTVERSION) @PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) @PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) @PKG_LIB_FILE@ $(PRJLIBNAME) << default-install: default-install-binaries default-install-libraries !if $(SYMBOLS) default-install: default-install-pdbs !endif # Again to deal with historical brokenness, there is some confusion # in terminlogy. For extensions, the "install-binaries" was used to # locate target directory for *binary shared libraries* and thus # the appropriate macro is LIB_INSTALL_DIR since BIN_INSTALL_DIR is # for executables (exes). On the other hand the "install-libraries" # target is for *scripts* and should have been called "install-scripts". default-install-binaries: $(PRJLIB) @echo Installing binaries to '$(LIB_INSTALL_DIR)' @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL # Alias for default-install-scripts default-install-libraries: default-install-scripts default-install-scripts: $(OUT_DIR)\pkgIndex.tcl @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) default-install-stubs: @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL default-install-pdbs: @echo Installing PDBs to '$(LIB_INSTALL_DIR)' @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)" @$(CPY) "$(OUT_DIR)\*.pdb" "$(LIB_INSTALL_DIR)\" default-install-docs-html: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)" default-install-docs-n: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' |
︙ | ︙ |
Changes to win/tcl.m4.
︙ | ︙ | |||
681 682 683 684 685 686 687 | LIBFLAGSUFFIX="\${DBGX}" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | LIBFLAGSUFFIX="\${DBGX}" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" CFLAGS_WARNING="-Wall -Wwrite-strings -Wsign-compare -Wdeclaration-after-statement -Wpointer-arith" LDFLAGS_DEBUG= LDFLAGS_OPTIMIZE= # Specify the CC output file names based on the target name CC_OBJNAME="-o \[$]@" CC_EXENAME="-o \[$]@" |
︙ | ︙ | |||
1266 1267 1268 1269 1270 1271 1272 | done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" | | | | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" ZIP_PROG_VFSSEARCH="*" AC_MSG_RESULT([Found INFO Zip in environment]) # Use standard arguments for zip else # It is not an error if an installed version of Zip can't be located. # We can use the locally distributed minizip instead ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" ZIP_PROG_OPTIONS="-o -r" ZIP_PROG_VFSSEARCH="*" ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" AC_MSG_RESULT([No zip found on PATH building minizip]) fi AC_SUBST(ZIP_PROG) AC_SUBST(ZIP_PROG_OPTIONS) AC_SUBST(ZIP_PROG_VFSSEARCH) AC_SUBST(ZIP_INSTALL_OBJS) ]) |
Changes to win/tkWinButton.c.
︙ | ︙ | |||
401 402 403 404 405 406 407 | } } /* * Compute width of default ring and offset for pushed buttons. */ | | > > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | } } /* * Compute width of default ring and offset for pushed buttons. */ if (butPtr->type == TYPE_LABEL) { defaultWidth = butPtr->highlightWidth; offset = 0; } else if (butPtr->type == TYPE_BUTTON) { defaultWidth = ((butPtr->defaultState == DEFAULT_ACTIVE) ? butPtr->highlightWidth : 0); offset = 1; } else { defaultWidth = 0; if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { offset = 1; |
︙ | ︙ | |||
755 756 757 758 759 760 761 762 763 | Tk_Draw3DRectangle(tkwin, pixmap, border, defaultWidth, defaultWidth, Tk_Width(tkwin) - 2*defaultWidth, Tk_Height(tkwin) - 2*defaultWidth, butPtr->borderWidth, relief); } if (defaultWidth != 0) { dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state); TkWinFillRect(dc, 0, 0, Tk_Width(tkwin), defaultWidth, | > > > > > > > | | | | | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 | Tk_Draw3DRectangle(tkwin, pixmap, border, defaultWidth, defaultWidth, Tk_Width(tkwin) - 2*defaultWidth, Tk_Height(tkwin) - 2*defaultWidth, butPtr->borderWidth, relief); } if (defaultWidth != 0) { int highlightColor; dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state); if (butPtr->type == TYPE_LABEL) { highlightColor = (int) Tk_3DBorderColor(butPtr->highlightBorder)->pixel; } else { highlightColor = (int) butPtr->highlightColorPtr->pixel; } TkWinFillRect(dc, 0, 0, Tk_Width(tkwin), defaultWidth, highlightColor); TkWinFillRect(dc, 0, 0, defaultWidth, Tk_Height(tkwin), highlightColor); TkWinFillRect(dc, 0, Tk_Height(tkwin) - defaultWidth, Tk_Width(tkwin), defaultWidth, highlightColor); TkWinFillRect(dc, Tk_Width(tkwin) - defaultWidth, 0, defaultWidth, Tk_Height(tkwin), highlightColor); TkWinReleaseDrawableDC(pixmap, dc, &state); } if (butPtr->flags & GOT_FOCUS) { Tk_SetCaretPos(tkwin, x, y, 0 /* not used */); } |
︙ | ︙ |
Changes to win/ttkWinXPTheme.c.
︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 | static int GetSysFlagFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *resultPtr) { static const char *names[] = { "SM_CXBORDER", "SM_CYBORDER", "SM_CXVSCROLL", "SM_CYVSCROLL", "SM_CXHSCROLL", "SM_CYHSCROLL", "SM_CXMENUCHECK", "SM_CYMENUCHECK", "SM_CXMENUSIZE", "SM_CYMENUSIZE", "SM_CXSIZE", "SM_CYSIZE", "SM_CXSMSIZE", | | | 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 | static int GetSysFlagFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *resultPtr) { static const char *names[] = { "SM_CXBORDER", "SM_CYBORDER", "SM_CXVSCROLL", "SM_CYVSCROLL", "SM_CXHSCROLL", "SM_CYHSCROLL", "SM_CXMENUCHECK", "SM_CYMENUCHECK", "SM_CXMENUSIZE", "SM_CYMENUSIZE", "SM_CXSIZE", "SM_CYSIZE", "SM_CXSMSIZE", "SM_CYSMSIZE", NULL }; int flags[] = { SM_CXBORDER, SM_CYBORDER, SM_CXVSCROLL, SM_CYVSCROLL, SM_CXHSCROLL, SM_CYHSCROLL, SM_CXMENUCHECK, SM_CYMENUCHECK, SM_CXMENUSIZE, SM_CYMENUSIZE, SM_CXSIZE, SM_CYSIZE, SM_CXSMSIZE, SM_CYSMSIZE }; |
︙ | ︙ |