Tk_SetOptions(3tk)

πŸŽ€ Tk_SetOptions β€” process configuration options πŸŽ€

okay bestie, welcome to the <strong>Tk Library Procedures</strong> section of the manual</strong> β€” this is the whole friend group that handles configuration options. Like, the entire squad that lets widgets read and write their config values without you losing your mind. πŸ’–


✨ NAME ✨

Tk_CreateOptionTable, Tk_DeleteOptionTable, Tk_InitOptions, Tk_SetOptions, Tk_FreeSavedOptions, Tk_RestoreSavedOptions, Tk_GetOptionValue, Tk_GetOptionInfo, Tk_FreeConfigOptions β€” process configuration options πŸ¦‹


🌸 SYNOPSIS 🌸

#include <tk.h>

Tk_OptionTable
Tk_CreateOptionTable(interp, templatePtr)

Tk_DeleteOptionTable(optionTable)

int
Tk_InitOptions(interp, recordPtr, optionTable, tkwin)

int
Tk_SetOptions(interp, recordPtr, optionTable, objc, objv, tkwin, savePtr, maskPtr)

Tk_FreeSavedOptions(savedPtr)

Tk_RestoreSavedOptions(savedPtr)

Tcl_Obj *
Tk_GetOptionValue(interp, recordPtr, optionTable, namePtr, tkwin)

Tcl_Obj *
Tk_GetOptionInfo(interp, recordPtr, optionTable, namePtr, tkwin)

Tk_FreeConfigOptions(recordPtr, optionTable, tkwin)

nine functions, one header, zero drama. slay. πŸ’…


πŸ’œ ARGUMENTS πŸ’œ

  • Tcl_Interp *interp (in) β€” a Tcl interpreter. ngl, most of these procedures only use it for returning error messages, and if it's NULL then no error messages get returned at all, periodt. The one exception: for Tk_CreateOptionTable this value cannot be NULL, because it tells you which interpreter the option table is gonna live in. 🫢
  • const Tk_OptionSpec *templatePtr (in) β€” points to an array of static info describing which configuration options are supported. It's literally the blueprint you use to build a Tk_OptionTable. Heads up though: whatever this argument points to must exist for the entire lifetime of the Tk_OptionTable β€” so don't go freeing it, bestie. πŸ™ˆ
  • Tk_OptionTable optionTable (in) β€” the token for an option table. It must have come back from an earlier call to Tk_CreateOptionTable. No bootlegging your own. πŸ’€
  • void *recordPtr (in/out) β€” points to the structure where the values of the configuration options are stored. Fields of this record get modified by stuff like Tk_SetOptions, and read by stuff like Tk_GetOptionValue. It's giving main character, honestly. ✨
  • Tk_Window tkwin (in) β€” for options like TK_OPTION_COLOR, this argument says which window the option is gonna be used in. If your optionTable doesn't use any window-dependent options, you can pass a NULL value here and nobody will come for you. πŸ¦‹
  • Tcl_Size objc (in) β€” the number of values in objv. Just the count. That's it, that's the whole job. πŸŽ€
  • Tcl_Obj *const *objv (in) β€” command-line arguments for setting configuring options. The actual receipts. πŸ’…
  • Tk_SavedOptions *savePtr (out) β€” if it's not NULL, the structure it points to gets filled in with the old values of any options that were modified. And the old values are restored automatically if an error occurs inside Tk_SetOptions. built-in undo, we love to see it 😭
  • int *maskPtr (out) β€” if it's not NULL, the word that maskPtr points to gets filled in with the bit-wise OR of the typeMask fields for the options that were modified. πŸ”₯
  • Tk_SavedOptions *savedPtr (in/out) β€” points to a structure that was previously filled in by Tk_SetOptions with old values of modified options. So like, the leftovers from last time. πŸ“
  • Tcl_Obj *namePtr (in) β€” the value of this object is the name of a particular option. If NULL is passed to Tk_GetOptionInfo, then info gets returned for all the options β€” the whole menu, bestie. But it must not be NULL when you call Tk_GetOptionValue. Different rules for different functions, iykyk. ⭐
  • type name type (in) β€” the name of the type of a record. 🧚
  • field name field (in) β€” the name of a field in records of type type. πŸ’œ

and that's the setup, the header file, and every single argument accounted for β€” no skips, no summaries, we keep <strong>everything</strong> in this house πŸ‘‘

✨ DESCRIPTION ✨

okay bestie, gather round, because these procedures are literally the whole backstage crew for parsing configuration options β€” like, the ones Tk widgets have. You hand them a description of which options exist, and they handle every single detail of parsing those options and tucking their values into a C structure that lives alongside the widget or object. πŸ’–

They were designed mainly for widgets in Tk, but no cap, you can also use them for other kinds of objects that have configuration options. In the rest of this manual page, "widget" means the object whose options are being managed β€” and yeah, in practice the object might not actually be a widget at all. And "widget record"? That's the C-level structure where info about a particular widget or object gets stored. πŸ“¦


🌸 the easiest way to learn this (fr fr)

ngl, the easiest way to figure out how to use these procedures is to just look at a working example. In Tk, the simplest one is the code that implements the button family of widgets, which lives in tkButton.c. Other examples are hanging out in tkSquare.c and tkMenu.c. Go peek at them, it's giving tutorial energy. πŸ‘€βœ¨

πŸŽ€ templates & the static array

To use these procedures, the code implementing the widget has to contain a static array of Tk_OptionSpec structures. That array is a template describing all the options supported by that class of widget β€” and yes, there's a separate template for each kind of widget. The template holds stuff like the name of each option, its type, its default value, and where the value of the option gets stored in the widget record. More deets in TEMPLATES below. πŸ“

πŸ’… runtime info & Tk_CreateOptionTable

To process configuration options efficiently, the static template has to be augmented with extra information that's only available at runtime. The procedure Tk_CreateOptionTable builds that dynamic info from the template and returns a Tk_OptionTable token that describes both the static and the dynamic info. Every other procedure β€” like Tk_SetOptions β€” takes a Tk_OptionTable token as an argument.

Typically, Tk_CreateOptionTable gets called the first time a widget of a particular class is created, and the resulting Tk_OptionTable is reused forever after for all widgets of that class. 🫢

One important thing: a Tk_OptionTable may be used only in a single interpreter β€” the one given by the interp argument to Tk_CreateOptionTable. No sharing across interpreters, periodt.

When an option table is no longer needed, Tk_DeleteOptionTable should be called to free all of its resources. And good news: all the option tables for a Tcl interpreter are freed automatically if the interpreter is deleted. iconic cleanup behavior. 🧹

πŸ¦‹ Tk_InitOptions

Tk_InitOptions gets invoked when a new widget is created, to set the default values. It's passed a token for an option table (optionTable) and a pointer to a widget record (recordPtr) β€” that's the C structure holding info about this widget.

It uses the info in the option table to pick an appropriate default for each option, then stores that default value directly into the widget record, overwriting any information that was already sitting there. πŸ’₯

Tk_InitOptions normally returns TCL_OK. If an error happened while setting the default values (e.g., because a default value was erroneous) then TCL_ERROR is returned and an error message is left in interp's result β€” that is, if interp is not NULL.

And for any widget's configuration option that has TK_OPTION_DONT_SET_DEFAULT set in its flags field, all that initialization above is fully skipped. See below. πŸ™ˆ

⭐ Tk_SetOptions

Tk_SetOptions gets invoked to modify configuration options based on information specified in a Tcl command. That command might be one that creates a brand new widget, or one that modifies options on an existing widget. The objc and objv arguments describe the values of the arguments from the Tcl command.

objv must contain an even number of objects: the first object of each pair gives the name of an option, and the second object gives the new value for that option. Tk_SetOptions looks up each name in optionTable, checks that the new value conforms to the type in optionTable, and stores the value into the widget record given by recordPtr. 🎯

It normally returns TCL_OK. If an error occurred (like an unknown option name or an illegal option value) then TCL_ERROR is returned and an error message is left in interp's result if interp is not NULL.

the two extra features (this is the good part)

1. the maskPtr glow-up πŸ’«

If the maskPtr argument is not NULL, then it points to an integer value that gets filled in with info about which options were modified.

Here's the tea: for each option in the template passed to Tk_CreateOptionTable there's a typeMask field. The bits of this field are defined by the code that implements the widget. For example, each bit might correspond to a particular configuration option. Alternatively, bits might be used functionally β€” like, one bit might be used for redisplay: all options that affect the widget's display, such that changing the option requires the widget to be redisplayed, might have that bit set. Another bit might indicate that the geometry of the widget must be recomputed, and so on. 🧠

Tk_SetOptions OR's together the typeMask fields from all the options that were modified and returns this value at *maskPtr. The caller can then use that info to optimize itself so that, for example, it does not redisplay the widget if the modified options don't affect the widget's appearance. main character optimization energy, honestly. πŸ‘‘

2. error recovery, aka the undo button 😭

If an error occurs while processing configuration options, this feature makes it possible to restore all the configuration options to their previous values. Errors can happen either while processing options in Tk_SetOptions or later in the caller.

In many cases the caller does additional processing after Tk_SetOptions returns. For example, it might use an option value to set a trace on a variable and may detect an error if the variable is an array instead of a scalar. πŸ˜΅πŸ’«

Error recovery is enabled by passing in a non-NULL value for the savePtr argument to Tk_SetOptions. That should be a pointer to an uninitialized Tk_SavedOptions structure on the caller's stack. Tk_SetOptions overwrites the structure pointed to by savePtr with information about the old values of any options modified by the procedure.

If Tk_SetOptions returns successfully, the caller uses that structure in one of two ways:

  1. If the caller completes its processing of the new options without any errors, then it must pass the structure to Tk_FreeSavedOptions so that the old values can be freed. 🌈
  2. If the caller detects an error in its processing of the new options, then it should pass the structure to Tk_RestoreSavedOptions, which will copy the old values back into the widget record and free the new values. 🫧

If Tk_SetOptions itself detects an error, then it automatically restores any options that had already been modified and leaves *savePtr in an empty state β€” the caller need not call either Tk_FreeSavedOptions or Tk_RestoreSavedOptions. so considerate of it honestly.

⚠️ But bestie, listen: if the savePtr argument to Tk_SetOptions is NULL, then Tk_SetOptions frees each old option value immediately when it sets a new value for the option. In that case, if an error occurs in the third option, the old values for the first two options cannot be restored. Gone. Poof. πŸ’€ No takebacks.

πŸ’œ Tk_GetOptionValue

Tk_GetOptionValue returns the current value of a configuration option for a particular widget. The namePtr argument contains the name of an option. It uses optionTable to look up the option and extract its value from the widget record pointed to by recordPtr, then returns an object containing that value. 🎁

If an error occurs (e.g., because namePtr contains an unknown option name) then NULL is returned and an error message is left in interp's result β€” unless interp is NULL.

🌸 Tk_GetOptionInfo

Tk_GetOptionInfo returns information about configuration options in a form suitable for configure widget commands. ✨

If the namePtr argument is not NULL, it points to an object that gives the name of a configuration option. In that case, Tk_GetOptionInfo returns an object containing a list with five elements, which are:

  1. the name of the option,
  2. the name and class used for the option in the option database,
  3. the default value for the option,
  4. the current value for the option.

Wait, that's four things but five elements β€” because item 2 covers both the name and the class. iykyk. 😌

If the namePtr argument is NULL, then Tk_GetOptionInfo returns information about all options in the form of a list of lists; each sublist describes one option.

synonym options get special treatment πŸ‘―

Synonym options are handled differently depending on whether namePtr is NULL:

  • If namePtr is NULL, then the sublist for each synonym option has only two elements: the name of the option and the name of the other option that it refers to.
  • If namePtr is non-NULL and names a synonym option, then the object returned is the five-element list for the other option that the synonym refers to.

If an error occurs (e.g., because namePtr contains an unknown option name) then NULL is returned and an error message is left in interp's result unless interp is NULL.

πŸŽ€ Tk_FreeConfigOptions

Tk_FreeConfigOptions must be invoked when a widget is deleted. It frees all of the resources associated with any of the configuration options defined in recordPtr by optionTable. clean up after yourself, bestie, it's the bare minimum. πŸ’–

✨ TEMPLATES ✨

okay bestie, gather round because this part is lowkey the blueprint for how widgets get their options. The array of Tk_OptionSpec structures that you pass to Tk_CreateOptionTable through its templatePtr argument? Yeah, that describes the configuration options supported by a particular class of widgets. periodt. Each structure is one single configuration option, and it has these fields:

typedef struct {
    Tk_OptionType type;
    const char *optionName;
    const char *dbName;
    const char *dbClass;
    const char *defValue;
    Tcl_Size objOffset;
    Tcl_Size internalOffset;
    int flags;
    const void *clientData;
    int typeMask;
} Tk_OptionSpec;
  • type β€” tells you what kind of config option this is (like TK_OPTION_COLOR for a color value, or TK_OPTION_INT for an integer value). It determines how the option's value gets parsed β€” more on that below, iykyk.
  • optionName β€” a string like -font or -bg. It's the name used for the option in Tcl commands and passed to procedures via the objc or namePtr arguments.
  • dbName and dbClass β€” used by Tk_InitOptions to look up a default value for this option in the option database. If dbName is NULL, then the option database is not used by Tk_InitOptions for this option.
  • defValue β€” specifies a default value for this config option if no value is specified in the option database.
  • objOffset and internalOffset β€” indicate where to store the value of this option in widget records (more on this below). Their values should always be generated with the offsetof macro.
  • flags β€” contains additional information to control the processing of this configuration option (see below for details).
  • clientData β€” provides additional type-specific data needed by certain types. For instance, for TK_OPTION_COLOR types, clientData is a string giving the default value to use on monochrome displays. See the descriptions of the different types below for details.
  • typeMask β€” used by Tk_SetOptions to return information about which options were modified; see the description of Tk_SetOptions above for details.

Okay so when Tk_InitOptions and Tk_SetOptions store the value of an option into the widget record, they can do it in either of two ways. If the objOffset field of the Tk_OptionSpec is greater than or equal to zero, then the value of the option is stored as a (Tcl_Obj *) at the location in the widget record given by objOffset. If the internalOffset field of the Tk_OptionSpec is greater than or equal to zero, then the value of the option is stored in a type-specific internal form at the location in the widget record given by internalOffset. For example, if the option's type is TK_OPTION_INT then the internal form is an integer. If the objOffset or internalOffset field is negative then the value is not stored in that form. At least one of the offsets must be greater than or equal to zero. no cap.

🚩 The flags field 🚩

The flags field consists of one or more bits ORed together. The following flags are supported:

  • TK_OPTION_NULL_OK β€” If this bit is set for an option then an empty string will be accepted as the value for the option and the resulting internal form will be a NULL pointer, a zero value, or None, depending on the type of the option. If the flag is not set then empty strings will result in errors. TK_OPTION_NULL_OK is typically used to allow a feature to be turned off entirely, e.g. set a cursor value to None so that a window simply inherits its parent's cursor. Not all option types support the TK_OPTION_NULL_OK flag; for those that do, there is an explicit indication of that fact in the descriptions below.
  • TK_OPTION_DONT_SET_DEFAULT β€” If this bit is set for an option then no default value will be set in Tk_InitOptions for this option. Neither the option database, nor any system default value, nor optionTable are used to give a default value to this option. Instead it is assumed that the caller has already supplied a default value in the widget code.
  • TK_OPTION_ENUM_VAR β€” If this value is set for an option, then it indicates that the internalOffset points to an enum variable instead of an int variable. Only useful in combination with TK_OPTION_STRING_TABLE, TK_OPTION_BOOLEAN, TK_OPTION_ANCHOR, TK_OPTION_JUSTIFY, or TK_OPTION_ANCHOR. (yes it says TK_OPTION_ANCHOR twice, bestie β€” we keep it exactly as the original)
  • TK_OPTION_VAR(type) β€” If this value is set for an option, then it indicates that the internalOffset points to a type variable instead of an int variable. Only useful in combination with TK_OPTION_STRING_TABLE or TK_OPTION_BOOLEAN, or as TK_OPTION_VAR(Tcl_Size) with TK_OPTION_INT.

🧬 The type field 🧬

Now the main character: the type field of each Tk_OptionSpec structure determines how to parse the value of that configuration option. The legal values for type, and the corresponding actions, are described below. If the type requires a tkwin value to be passed into procedures like Tk_SetOptions, or if it uses the clientData field of the Tk_OptionSpec, then it is indicated explicitly; if not mentioned, the type requires neither tkwin nor clientData.

  • TK_OPTION_ANCHOR β€” The value must be a standard anchor position such as ne or center. The internal form is a Tk_Anchor value like the ones returned by Tk_GetAnchorFromObj. This option type supports the TK_OPTION_NULL_OK flag; if the empty string is specified as the value for the option, the integer relief value is set to TK_ANCHOR_NULL.
  • TK_OPTION_BITMAP β€” The value must be a standard Tk bitmap name. The internal form is a Pixmap token like the ones returned by Tk_AllocBitmapFromObj. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions, and it supports the TK_OPTION_NULL_OK flag.
  • TK_OPTION_BOOLEAN β€” The value must be a standard boolean value such as true or no. The internal form is an integer with value 0 or 1. Note that if the objOffset field is not used, information about the original value of this option will be lost. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to -1.
  • TK_OPTION_BORDER β€” The value must be a standard color name such as red or #ff8080. The internal form is a Tk_3DBorder token like the ones returned by Tk_Alloc3DBorderFromObj. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions, and it supports the TK_OPTION_NULL_OK flag.
  • TK_OPTION_COLOR β€” The value must be a standard color name such as red or #ff8080. The internal form is an (XColor *) token like the ones returned by Tk_AllocColorFromObj. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions, and it supports the TK_OPTION_NULL_OK flag.
  • TK_OPTION_CURSOR β€” The value must be a standard cursor name such as cross or @foo. The internal form is a Tk_Cursor token like the ones returned by Tk_AllocCursorFromObj. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions, and when the option is set the cursor for the window is changed by calling XDefineCursor. This option type also supports the TK_OPTION_NULL_OK flag.
  • TK_OPTION_CUSTOM β€” This option allows applications to define new option types. The clientData field of the entry points to a structure defining the new option type. See the section CUSTOM OPTION TYPES below for details.
  • TK_OPTION_DOUBLE β€” The string value must be a floating-point number in the format accepted by strtol. The internal form is a C double value. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to NaN.
  • TK_OPTION_END β€” Marks the end of the template. There must be a Tk_OptionSpec structure with type TK_OPTION_END at the end of each template. If the clientData field of this structure is not NULL, then it points to an additional array of Tk_OptionSpec's, which is itself terminated by another TK_OPTION_END entry. Templates may be chained arbitrarily deeply. This feature allows common options to be shared by several widget classes.
  • TK_OPTION_FONT β€” The value must be a standard font name such as Times 16. The internal form is a Tk_Font handle like the ones returned by Tk_AllocFontFromObj. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions, and it supports the TK_OPTION_NULL_OK flag.
  • TK_OPTION_INT β€” The string value must be an integer in the format accepted by strtol (e.g. 0 and 0x prefixes may be used to specify octal or hexadecimal numbers, respectively). The internal form is a C int value. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to INT_MIN.
  • TK_OPTION_INDEX β€” The string value must be an index in the format accepted by Tcl_GetIntForIndex() or the empty string. The internal form is a C int value. If the string starts with -, the internal representation will be set to INT_MIN. If the string has the form end-???, then the result will be a negative number: -1 stands for end, -2 stands for end-1 and so on. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to INT_MIN.
  • TK_OPTION_JUSTIFY β€” The value must be a standard justification value such as left. The internal form is a Tk_Justify like the values returned by Tk_GetJustifyFromObj. This option type supports the TK_OPTION_NULL_OK flag; if the empty string is specified as the value for the option, the integer relief value is set to TK_JUSTIFY_NULL.
  • TK_OPTION_PIXELS β€” The value must specify a screen distance such as 2i or 6.4. The internal form is an integer value giving a distance in pixels, like the values returned by Tk_GetPixelsFromObj. Note that if the objOffset field is not used, information about the original value of this option will be lost. See OBJOFFSET VS. INTERNALOFFSET below for details. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to INT_MIN.

πŸ’… TK_OPTION_RELIEF πŸ’…

Okay so for this one, the value has to be a standard relief like raised. The internal form? It's an integer relief value, like TK_RELIEF_RAISED. This option type supports the TK_OPTION_NULL_OK flag β€” and if a NULL value gets set, the internal representation is set to TK_RELIEF_NULL. Periodt. πŸ’–

✨ TK_OPTION_STRING ✨

The value can be literally any string, bestie. The internal form is a (char *) pointer that points to a dynamically allocated copy of the value. This option type supports the TK_OPTION_NULL_OK flag too. Slay. πŸŽ€

πŸ¦‹ TK_OPTION_STRING_TABLE πŸ¦‹

For this type, clientData is a pointer to an array of strings suitable for passing to Tcl_GetIndexFromObj. The value must be one of the strings in the table, or a unique abbreviation of one of the strings. The internal form is an integer giving the index into the table of the matching string, like the return value from Tcl_GetStringFromObj. This option type supports the TK_OPTION_NULL_OK flag; if a NULL value is set, the internal representation is set to -1. No cap. πŸ”₯

🌈 TK_OPTION_SYNONYM 🌈

This type is used to provide alternative names for an option (for example, -bg is often used as a synonym for -background). The clientData field is a string that gives the name of another option in the same table. Whenever the synonym option is used, the information from the other option will be used instead. It's giving efficient. πŸ’…

πŸ‘‘ TK_OPTION_WINDOW πŸ‘‘

The value must be a window path name. The internal form is a Tk_Window token for the window. This option type requires tkwin to be supplied to procedures such as Tk_SetOptions (in order to identify the application), and it supports the TK_OPTION_NULL_OK flag. Iconic behavior, honestly. 🫢


πŸ’– STORAGE MANAGEMENT ISSUES πŸ’–

Okay so if a field of a widget record has its offset stored in the objOffset or internalOffset field of a Tk_OptionSpec structure, then the procedures described here will handle all of the storage allocation and resource management issues associated with the field. Lowkey a whole service. ✨

When the value of an option is changed, Tk_SetOptions (or Tk_FreeSavedOptions) will automatically free any resources associated with the old value, such as Tk_Fonts for TK_OPTION_FONT options or dynamically allocated memory for TK_OPTION_STRING options. It really said "I'll clean up your mess." πŸ’…

For an option stored as an object using the objOffset field of a Tk_OptionSpec, the widget record shares the object pointed to by the objv value from the call to Tk_SetOptions. The reference count for this object is incremented when a pointer to it is stored in the widget record and decremented when the option is modified. When the widget is deleted Tk_FreeConfigOptions should be invoked; it will free the resources associated with all options and decrement reference counts for any objects. Bestie, this is the whole lifecycle. πŸ¦‹

However β€” and this is important, fr fr β€” the widget code is responsible for storing NULL or None in all pointer and token fields before invoking Tk_InitOptions. This is needed to allow proper cleanup in the rare case where an error occurs in Tk_InitOptions. Don't skip this step, iykyk. 😭

🌟 OBJOFFSET VS. INTERNALOFFSET 🌟

In most cases it is simplest to use the internalOffset field of a Tk_OptionSpec structure and not the objOffset field. This makes the internal form of the value immediately available to the widget code so the value does not have to be extracted from an object each time it is used. Highkey convenient. πŸ’–

However, there are two cases where the objOffset field is useful. The first case is for TK_OPTION_PIXELS options. In this case, the internal form is an integer pixel value that is valid only for a particular screen. If the value of the option is retrieved, it will be returned as a simple number. For example, after the command .b configure -borderwidth 2m, the command .b configure -borderwidth might return 7, which is the integer pixel value corresponding to 2m. Unfortunately, this loses the original screen-independent value. Thus for TK_OPTION_PIXELS options it is better to use the objOffset field. In this case the original value of the option is retained in the object and can be returned when the option is retrieved. It might seem convenient to use the internalOffset field as well, so that the integer value is immediately available for use in the widget code. But if scaling is involved, internalOffset won't change value when the scaling changes. Therefore it is better always to use Tk_GetPixelsFromObj to extract the integer value from the object whenever it is needed. Note: the problem of losing information on retrievals exists only for TK_OPTION_PIXELS options. That's the tea. πŸ“

The second reason to use the objOffset field is in order to implement new types of options not supported by these procedures. To implement a new type of option, you can use TK_OPTION_STRING as the type in the Tk_OptionSpec structure and set the objOffset field but not the internalOffset field. Then, after calling Tk_SetOptions, convert the object to internal form yourself. DIY queen behavior. πŸ‘‘

Ttk widgets do not support the internalOffset machinery. Option values of Ttk widgets are always stored as (Tcl_Obj *), meaning that the objOffset field must be used. So if you're in Ttk land, that's the vibe. 🌈

🌈 CUSTOM OPTION TYPES 🌈

okay bestie, this is the glow-up part: you can literally make your own option types. Not just the built-in ones. You write procedures that parse, print, free, and restore saved copies of your type, then you build a structure that points at them. iconic behavior. πŸ’…

typedef struct {
    const char *name;
    Tk_CustomOptionSetProc *setProc;
    Tk_CustomOptionGetProc *getProc;
    Tk_CustomOptionRestoreProc *restoreProc;
    Tk_CustomOptionFreeProc *freeProc;
    void *clientData;
} Tk_ObjCustomOption;

typedef int Tk_CustomOptionSetProc(
    void *clientData,
    Tcl_Interp *interp,
    Tk_Window tkwin,
    Tcl_Obj **valuePtr,
    char *recordPtr,
    Tcl_Size internalOffset,
    char *saveInternalPtr,
    int flags);

typedef Tcl_Obj *Tk_CustomOptionGetProc(
    void *clientData,
    Tk_Window tkwin,
    char *recordPtr,
    Tcl_Size internalOffset);

typedef void Tk_CustomOptionRestoreProc(
    void *clientData,
    Tk_Window tkwin,
    char *internalPtr,
    char *saveInternalPtr);

typedef void Tk_CustomOptionFreeProc(
    void *clientData,
    Tk_Window tkwin,
    char *internalPtr);

The Tk_ObjCustomOption structure contains six fields, no more no less: a name for the custom option type; pointers to the four procedures; and a clientData value that gets handed to those procedures whenever they're invoked. The clientData value typically points to a structure holding info the procedures need while they're parsing and printing options. And heads up β€” restoreProc and freeProc may be NULL, which means "no function should be called for those operations." That's allowed, bestie, it's not a bug. 🫢


πŸŽ€ the setProc procedure

setProc gets invoked by Tk_SetOptions to convert a Tcl_Obj into an internal representation and store the resulting value in the widget record. The arguments are:

  • clientData β€” A copy of the clientData field in the Tk_ObjCustomOption structure.
  • interp β€” A pointer to a Tcl interpreter, used for error reporting.
  • Tkwin β€” A copy of the tkwin argument to Tk_SetOptions.
  • valuePtr β€” A pointer to a reference to a Tcl_Obj describing the new value for the option; it could have been specified explicitly in the call to Tk_SetOptions or it could come from the option database or a default. If the objOffset for the option is non-negative (the option value is stored as a (Tcl_Obj *) in the widget record), the Tcl_Obj pointer referenced by valuePtr is the pointer that will be stored at the objOffset for the option. setProc may modify the value if necessary; for example, setProc may change the value to NULL to support the TK_OPTION_NULL_OK flag.
  • recordPtr β€” A pointer to the start of the widget record to modify.
  • internalOffset β€” Offset in bytes from the start of the widget record to the location where the internal representation of the option value is to be placed.
  • saveInternalPtr β€” A pointer to storage allocated in a Tk_SavedOptions structure for the internal representation of the original option value. Before setting the option to its new value, setProc should set the value referenced by saveInternalPtr to the original value of the option in order to support Tk_RestoreSavedOptions.
  • flags β€” A copy of the flags field in the Tk_OptionSpec structure for the option.

setProc returns a standard Tcl result: TCL_OK to indicate successful processing, or TCL_ERROR to indicate a failure of any kind. An error message may be left in the Tcl interpreter given by interp in the case of an error. πŸ’–


✨ the getProc procedure

getProc gets invoked by Tk_GetOptionValue and Tk_GetOptionInfo to retrieve a Tcl_Obj representation of the internal representation of an option.

  • The clientData argument is a copy of the clientData field in the Tk_ObjCustomOption structure.
  • Tkwin is a copy of the tkwin argument to Tk_GetOptionValue or Tk_GetOptionInfo.
  • RecordPtr is a pointer to the beginning of the widget record to query.
  • InternalOffset is the offset in bytes from the beginning of the widget record to the location where the internal representation of the option value is stored.

And getProc must return a pointer to a Tcl_Obj representing the value of the option. no dodging that one, bestie. 🌸


πŸ’« the restoreProc procedure

restoreProc gets invoked by Tk_RestoreSavedOptions to restore a previously saved internal representation of a custom option value.

  • The clientData argument is a copy of the clientData field in the Tk_ObjCustomOption structure.
  • Tkwin is a copy of the tkwin argument to Tk_GetOptionValue or Tk_GetOptionInfo.
  • InternalPtr is a pointer to the location where internal representation of the option value is stored.
  • SaveInternalPtr is a pointer to the saved value.

restoreProc must copy the value from saveInternalPtr to internalPtr to restore the value. And here's the lil treat: restoreProc need not free any memory associated with either internalPtr or saveInternalPtr β€” freeProc will be invoked to free that memory if necessary. restoreProc has no return value.


πŸ¦‹ the freeProc procedure

freeProc gets invoked by Tk_SetOptions and Tk_FreeSavedOptions to free any storage allocated for the internal representation of a custom option.

  • The clientData argument is a copy of the clientData field in the Tk_ObjCustomOption structure.
  • Tkwin is a copy of the tkwin argument to Tk_GetOptionValue or Tk_GetOptionInfo.
  • InternalPtr is a pointer to the location where the internal representation of the option value is stored.

The freeProc must free any storage associated with the option. freeProc has no return value. clean up after yourself, it's giving main character energy. 🧹✨


πŸ”‘ KEYWORDS πŸ”‘

anchor, bitmap, boolean, border, color, configuration option, cursor, double, font, integer, justify, pixels, relief, screen distance, synonym


aaaaand that's a wrap on the whole page, bestie!! πŸŽ‰ you just read all of Tk_SetOptions(3tk) β€” from Tk version 8.1, dated with the classic manpage date. go forth and configure some widgets, you absolute icon. πŸ’œπŸ‘‘

πŸ“¦ where this page comes from