Tk Source Code

Changes On Branch tip-679
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch tip-679 Excluding Merge-Ins

This is equivalent to a diff from 6773bd49 to 0436d8c2

2023-10-03
20:01
Made sure that themes missing the "-font" style setting for "Heading" or "Treeview" won't break the mclist.tcl Widget Demo script. check-in: 7b4d929f user: csaba tags: trunk, main
2023-09-29
12:31
merge trunk check-in: 6e002715 user: dgp tags: core-8-7-b1-rc
2023-09-27
18:38
Update canvas printing implmentation on macOS to address Apple's removal of PostScript conversion tools from OS check-in: bbdb1826 user: kevin_walzer tags: mac_cg_printing
2023-09-22
20:22
Document the new command in the manual page. Leaf check-in: 0436d8c2 user: sbron tags: tip-679
15:32
Start TIP #679 implementation check-in: fc178b78 user: sbron tags: tip-679
12:50
Small improvement in tkfbox.tcl. check-in: 6773bd49 user: csaba tags: trunk, main
10:41
Guarded the library script tkfbox.tcl against icon deletion (like in several Tk tests). check-in: 009b6887 user: csaba tags: trunk, main

Changes to doc/wm.n.

696
697
698
699
700
701
702


























703
704
705
706
707
708
709
source of the window's current position, or an empty string if
no source has been specified yet.  Most window managers interpret
.QW "no source"
as equivalent to \fBprogram\fR.
Tk will automatically set the position source to \fBuser\fR
when a \fBwm geometry\fR command is invoked, unless the source has
been set explicitly to \fBprogram\fR.


























.TP
\fBwm protocol \fIwindow\fR ?\fIname\fR? ?\fIcommand\fR?
.
This command is used to manage window manager protocols. The \fIname\fR
argument in the \fBwm protocol\fR command is the name of an atom corresponding
to a window manager protocol.  Examples include \fBWM_DELETE_WINDOW\fR or
\fBWM_SAVE_YOURSELF\fR or \fBWM_TAKE_FOCUS\fR.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
source of the window's current position, or an empty string if
no source has been specified yet.  Most window managers interpret
.QW "no source"
as equivalent to \fBprogram\fR.
Tk will automatically set the position source to \fBuser\fR
when a \fBwm geometry\fR command is invoked, unless the source has
been set explicitly to \fBprogram\fR.
.TP
\fBwm property \fIwindow\fR ?\fIname\fR? ?\fIvalue\fR? ?\fItype\fR? ?\fIwidth\fR?
.
This command provides access to the X properties of a Tk toplevel window.
The command is only available on the x11 windowing system.
If \fIname\fR and \fIvalue\fR are specified, the property is updated. The
\fItype\fR and \fIwidth\fR arguments may be used to specify in which format
the property value is to be stored.
Any valid atom name can be used for \fItype\fR. Common values include
\fBSTRING\fR, \fBINTEGER\fR, \fBCARDINAL\fR (i.e. unsigned integer), and
\fBATOM\fR. The special type \fBNone\fR causes the property to be deleted.
The default for \fItype\fR is \fBSTRING\fR.
Note that type names are case sensitive.
Allowed values for \fIwidth\fR are 8, 16, and 32. If omitted, \fIwidth\fR
defaults to 8 for \fBSTRING\fR and \fBUTF8-STRING\fR types, and to 32 for
all other types.
For properties consisting of 8-bit fields, \fIvalue\fR is interpreted as a
byte array. For 16-bit fields it must be specified as a list of integers.
For 32-bit fields, \fIvalue\fR is parsed as a list, where each element may
either be an integer or an atom name.
If \fIname\fR is specified, but no \fIvalue\fR, the current value of the
named property is returned, if set. The type and width of the property value
are returned in the \fB-propertytype\fR and \fB-propertyformat\fR return
options.
If not even the \fIname\fR argument is present, the command returns a list
of the names of all properties that currently exist for the toplevel window.
.TP
\fBwm protocol \fIwindow\fR ?\fIname\fR? ?\fIcommand\fR?
.
This command is used to manage window manager protocols. The \fIname\fR
argument in the \fBwm protocol\fR command is the name of an atom corresponding
to a window manager protocol.  Examples include \fBWM_DELETE_WINDOW\fR or
\fBWM_SAVE_YOURSELF\fR or \fBWM_TAKE_FOCUS\fR.

Changes to tests/wm.test.

118
119
120
121
122
123
124

125
126
127





128
129
130
131
132
133
134

stdWindow

test wm-1.1 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm
} -result {wrong # args: should be "wm option window ?arg ...?"}
# Next test will fail every time set of subcommands is changed

test wm-1.2 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm foo
} -result {bad option "foo": must be aspect, attributes, client, colormapwindows, command, deiconify, focusmodel, forget, frame, geometry, grid, group, iconbadge, iconbitmap, iconify, iconmask, iconname, iconphoto, iconposition, iconwindow, manage, maxsize, minsize, overrideredirect, positionfrom, protocol, resizable, sizefrom, stackorder, state, title, transient, or withdraw}





test wm-1.3 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm command
} -result {wrong # args: should be "wm option window ?arg ...?"}
test wm-1.4 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm aspect bogus
} -result {bad window path name "bogus"}
test wm-1.5 {Tk_WmObjCmd procedure, miscellaneous errors} -body {







>
|
|
|
>
>
>
>
>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

stdWindow

test wm-1.1 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm
} -result {wrong # args: should be "wm option window ?arg ...?"}
# Next test will fail every time set of subcommands is changed
if {[testConstraint x11]} {
    test wm-1.2 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
	wm foo
    } -result {bad option "foo": must be aspect, attributes, client, colormapwindows, command, deiconify, focusmodel, forget, frame, geometry, grid, group, iconbadge, iconbitmap, iconify, iconmask, iconname, iconphoto, iconposition, iconwindow, manage, maxsize, minsize, overrideredirect, positionfrom, property, protocol, resizable, sizefrom, stackorder, state, title, transient, or withdraw}
} else {
    test wm-1.2 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
	wm foo
    } -result {bad option "foo": must be aspect, attributes, client, colormapwindows, command, deiconify, focusmodel, forget, frame, geometry, grid, group, iconbadge, iconbitmap, iconify, iconmask, iconname, iconphoto, iconposition, iconwindow, manage, maxsize, minsize, overrideredirect, positionfrom, protocol, resizable, sizefrom, stackorder, state, title, transient, or withdraw}
}
test wm-1.3 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm command
} -result {wrong # args: should be "wm option window ?arg ...?"}
test wm-1.4 {Tk_WmObjCmd procedure, miscellaneous errors} -returnCodes error -body {
    wm aspect bogus
} -result {bad window path name "bogus"}
test wm-1.5 {Tk_WmObjCmd procedure, miscellaneous errors} -body {
1333
1334
1335
1336
1337
1338
1339




























































































1340
1341
1342
1343
1344
1345
1346
    wm positionfrom .t {}
    lappend result [wm positionfrom .t]
} -cleanup {
    destroy .t2
} -result {user program {}}






























































































### wm protocol ###
test wm-protocol-1.1 {usage} -returnCodes error -body {
    wm protocol
} -result {wrong # args: should be "wm option window ?arg ...?"}
test wm-protocol-1.2 {usage} -returnCodes error -body {
    wm protocol .t 1 2 3
} -result {wrong # args: should be "wm protocol window ?name? ?command?"}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
    wm positionfrom .t {}
    lappend result [wm positionfrom .t]
} -cleanup {
    destroy .t2
} -result {user program {}}


### wm property ###
test wm-property-1.1 {usage} -returnCodes error -constraints x11 -body {
    wm property
} -result {wrong # args: should be "wm option window ?arg ...?"}
test wm-property-1.2 {usage} -returnCodes error -constraints x11 -body {
    wm property .t 1 2 3 4 5
} -result {wrong # args: should be "wm property window ?name? ?value? ?type? ?width?"}
test wm-property-1.3 {usage} -returnCodes error -constraints x11 -body {
    wm property .t _TCL_TEST 42 CARDINAL 24
} -result {invalid width: 24}
test wm-property-1.4 {usage} -returnCodes error -constraints x11 -body {
    wm property .t _TCL_TEST "Some string" STRING 16
} -result {invalid width: 16}
test wm-property-1.5 {usage} -returnCodes error -constraints x11 -body {
    wm property .t _TCL_TEST {invalid "list''} INTEGER 16
} -result {unmatched open quote in list}
test wm-property-1.6 {usage} -returnCodes error -constraints x11 -body {
    wm property .t _TCL_TEST {xx yy zz} INTEGER 16
} -result {expected integer but got "xx"}
test wm-property-1.7 {usage} -returnCodes error -constraints x11 -body {
    wm property .t _TCL_TEST [lrepeat 66 99] INTEGER
} -result {too many elements}
test wm-property-1.8 {usage} -returnCodes error -constraints x11 -body {
    wm property .t WM_NAME "New name"
} -result {changing reserved property "WM_NAME" is not allowed}

test wm-property-2.1 {reading values} -constraints x11 -body {
    expr {"WM_NAME" in [wm property .t]}
} -result 1
test wm-property-2.2 {reading values} -constraints x11 -body {
    wm property .t WM_NAME
} -result "t"
test wm-property-2.3 {reading values} -constraints x11 -body {
    catch {wm property .t WM_NAME} data opts
    dict values [dict filter $opts key -property*]
} -result "STRING 8"
test wm-property-2.4 {reading values} -constraints x11 -body {
    catch {wm property .t WM_PROTOCOLS} data opts
    dict values [dict filter $opts key -property*]
} -result "ATOM 32"

test wm-property-3.1 {setting values} -constraints x11 -body {
    wm property .t _TCL_TEST "Some string"
    catch {wm property .t _TCL_TEST} data opts
    linsert [dict values [dict filter $opts key -property*]] 0 $data
} -result {{Some string} STRING 8}
test wm-property-3.2 {setting values} -constraints x11 -body {
    wm property .t _TCL_TEST [lrepeat 64 88] CARDINAL
    catch {wm property .t _TCL_TEST} data opts
    linsert [dict values [dict filter $opts key -property*]] 0 \
      [llength $data] [lsort -unique -integer $data]
} -result {64 88 CARDINAL 32}
test wm-property-3.3 {setting values} -constraints x11 -body {
    wm property .t _TCL_TEST {WM_STATE WM_PROTOCOLS _TCL_TEST_ATOM} ATOM
    lmap n [wm property .t _TCL_TEST] {winfo atomname $n}
} -result {WM_STATE WM_PROTOCOLS _TCL_TEST_ATOM}

test wm-property-4.1 {deleting values} -constraints x11 -body {
    wm property .t _TCL_TEST "Some string"
    wm property .t _TCL_TEST "Delete" None
    try {wm property .t _TCL_TEST} on ok {data opts} {
	linsert [dict values [dict filter $opts key -property*]] 0 $data
    }
} -result {{}}
test wm-property-4.2 {deleting values} -constraints x11 -body {
    wm property .t _TCL_TEST_NOTSET "Delete" None
    try {wm property .t _TCL_TEST_NOTSET} on ok {data opts} {
	linsert [dict values [dict filter $opts key -property*]] 0 $data
    }
} -result {{}}

test wm-property-5.1 {unmapped window} -constraints x11 -body {
    toplevel .t1
    wm property .t1
} -cleanup {
    destroy .t1
} -result {}
test wm-property-5.2 {unmapped window} -constraints x11 -body {
    toplevel .t1
    wm property .t1 WM_NAME
} -cleanup {
    destroy .t1
} -result {}
test wm-property-5.3 {unmapped window} -constraints x11 -body {
    toplevel .t1
    wm property .t1 _TCL_TEST "Some string"
    catch {wm property .t1 _TCL_TEST} data opts
    linsert [dict values [dict filter $opts key -property*]] 0 $data
} -cleanup {
    destroy .t1
} -result {{Some string} STRING 8}

### wm protocol ###
test wm-protocol-1.1 {usage} -returnCodes error -body {
    wm protocol
} -result {wrong # args: should be "wm option window ?arg ...?"}
test wm-protocol-1.2 {usage} -returnCodes error -body {
    wm protocol .t 1 2 3
} -result {wrong # args: should be "wm protocol window ?name? ?command?"}

Changes to unix/tkUnixWm.c.

34
35
36
37
38
39
40


41
42
43
44
45
46
47
				 * needs of the actual command. THIS MUST BE
				 * THE LAST FIELD OF THE STRUCTURE. */
} ProtocolHandler;

#define HANDLER_SIZE(cmdLength) \
    (offsetof(ProtocolHandler, command) + 1 + cmdLength)



/*
 * Data for [wm attributes] command:
 */

typedef struct {
    double alpha;		/* Transparency; 0.0=transparent, 1.0=opaque */
    int topmost;		/* Flag: true=>stay-on-top */







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
				 * needs of the actual command. THIS MUST BE
				 * THE LAST FIELD OF THE STRUCTURE. */
} ProtocolHandler;

#define HANDLER_SIZE(cmdLength) \
    (offsetof(ProtocolHandler, command) + 1 + cmdLength)

#define PROPMAXELEMENTS 64

/*
 * Data for [wm attributes] command:
 */

typedef struct {
    double alpha;		/* Transparency; 0.0=transparent, 1.0=opaque */
    int topmost;		/* Flag: true=>stay-on-top */
448
449
450
451
452
453
454



455
456
457
458
459
460
461
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmOverrideredirectCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmPositionfromCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,



			    Tcl_Obj *const objv[]);
static int		WmProtocolCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmResizableCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);







>
>
>







450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmOverrideredirectCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmPositionfromCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmPropertyCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmProtocolCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmResizableCmd(Tk_Window tkwin, TkWindow *winPtr,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
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
    Tk_Window tkwin = (Tk_Window)clientData;
    static const char *const optionStrings[] = {
	"aspect", "attributes", "client", "colormapwindows",
	"command", "deiconify", "focusmodel", "forget",
	"frame", "geometry", "grid", "group", "iconbadge", "iconbitmap",
	"iconify", "iconmask", "iconname", "iconphoto",
	"iconposition", "iconwindow", "manage", "maxsize",
	"minsize", "overrideredirect", "positionfrom",
	"protocol", "resizable", "sizefrom", "stackorder",
	"state", "title", "transient", "withdraw", NULL };
    enum options {
	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
	WMOPT_FRAME, WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP,
	WMOPT_ICONBADGE, WMOPT_ICONBITMAP,
	WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME, WMOPT_ICONPHOTO,
	WMOPT_ICONPOSITION, WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE,
	WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT, WMOPT_POSITIONFROM,

	WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM, WMOPT_STACKORDER,
	WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT, WMOPT_WITHDRAW };
    int index;
    const char *argv1;
    TkWindow *winPtr;
    Tk_Window targetWin;
    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;







|










>







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
    Tk_Window tkwin = (Tk_Window)clientData;
    static const char *const optionStrings[] = {
	"aspect", "attributes", "client", "colormapwindows",
	"command", "deiconify", "focusmodel", "forget",
	"frame", "geometry", "grid", "group", "iconbadge", "iconbitmap",
	"iconify", "iconmask", "iconname", "iconphoto",
	"iconposition", "iconwindow", "manage", "maxsize",
	"minsize", "overrideredirect", "positionfrom", "property",
	"protocol", "resizable", "sizefrom", "stackorder",
	"state", "title", "transient", "withdraw", NULL };
    enum options {
	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
	WMOPT_FRAME, WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP,
	WMOPT_ICONBADGE, WMOPT_ICONBITMAP,
	WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME, WMOPT_ICONPHOTO,
	WMOPT_ICONPOSITION, WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE,
	WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT, WMOPT_POSITIONFROM,
	WMOPT_PROPERTY,
	WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM, WMOPT_STACKORDER,
	WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT, WMOPT_WITHDRAW };
    int index;
    const char *argv1;
    TkWindow *winPtr;
    Tk_Window targetWin;
    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1141
1142
1143
1144
1145
1146
1147


1148
1149
1150
1151
1152
1153
1154
	return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_MINSIZE:
	return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_OVERRIDEREDIRECT:
	return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_POSITIONFROM:
	return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);


    case WMOPT_PROTOCOL:
	return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_RESIZABLE:
	return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_SIZEFROM:
	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STACKORDER:







>
>







1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
	return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_MINSIZE:
	return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_OVERRIDEREDIRECT:
	return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_POSITIONFROM:
	return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_PROPERTY:
	return WmPropertyCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_PROTOCOL:
	return WmProtocolCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_RESIZABLE:
	return WmResizableCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_SIZEFROM:
	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STACKORDER:
3133
3134
3135
3136
3137
3138
3139

















































































































































































































3140
3141
3142
3143
3144
3145
3146
	memcpy(protPtr->command, cmd, cmdLength + 1);
    }
    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
	UpdateWmProtocols(wmPtr);
    }
    return TCL_OK;
}


















































































































































































































/*
 *----------------------------------------------------------------------
 *
 * WmResizableCmd --
 *
 *	This function is invoked to process the "wm resizable" Tcl command.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
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
3208
3209
3210
3211
3212
3213
3214
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
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
	memcpy(protPtr->command, cmd, cmdLength + 1);
    }
    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
	UpdateWmProtocols(wmPtr);
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * WmPropertyCmd --
 *
 *	This function is invoked to process the "wm property" Tcl command. See
 *	the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

static int
WmPropertyCmd(
    TCL_UNUSED(Tk_Window),	/* Main window of the application. */
    TkWindow *winPtr,		/* Toplevel to work with */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    WmInfo *wmPtr = winPtr->wmInfoPtr;
    Atom property, type = XA_STRING;
    Atom XA_UTF8_STRING = Tk_InternAtom((Tk_Window)winPtr, "UTF8_STRING");
    int i, count, value, width = 0;
    const char *name;
    const unsigned char *bytes;
    unsigned char data8[PROPMAXELEMENTS * sizeof(long)];
    unsigned short *data16;
    unsigned long *data32;
    Tcl_Size length;
    Tcl_Obj **elements;

    if ((objc < 3) || (objc > 7)) {
	Tcl_WrongNumArgs(interp, 2, objv,
          "window ?name? ?value? ?type? ?width?");
	return TCL_ERROR;
    }
    if (objc == 3) {
	/*
	 * Return a list of all defined properties for the window.
	 */
	Tcl_Obj *resultObj = Tcl_NewObj();
        Atom *atoms;

        if (wmPtr->wrapperPtr != NULL) {
            atoms = XListProperties(wmPtr->wrapperPtr->display,
              wmPtr->wrapperPtr->window, &count);
        } else {
            count = 0;
        }

        for (i = 0; i < count; i++) {
            Tcl_ListObjAppendElement(NULL, resultObj, 
              Tcl_NewStringObj(Tk_GetAtomName((Tk_Window)winPtr,
                atoms[i]), -1));
        }
	Tcl_SetObjResult(interp, resultObj);
	return TCL_OK;
    }

    name = Tcl_GetString(objv[3]);
    property = Tk_InternAtom((Tk_Window)winPtr, name);

    if (objc == 4) {
	/*
	 * Return the value of a given property.
	 */

        int format;
        unsigned long nitems, remain;
        unsigned char *data;
        long maxLength = PROPMAXELEMENTS;

        if (wmPtr->wrapperPtr == NULL) return TCL_OK;

        if (GetWindowProperty(wmPtr->wrapperPtr, property, maxLength,
          AnyPropertyType, &type, &format, &nitems, &remain, &data)) {
            Tcl_Obj *options = Tcl_NewDictObj();
            Tcl_Obj *resultObj;
            const char *typeStr;

            count = nitems;
            switch (format) {
             case 8:
                Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(data, count));
                break;
             case 16:
                data16 = (unsigned short *)data;
                resultObj = Tcl_NewListObj(count, NULL);
                for (i = 0; i < count; i++) {
                    Tcl_ListObjAppendElement(NULL, resultObj,
                      Tcl_NewIntObj(data16[i]));
                }
                Tcl_SetObjResult(interp, resultObj);
                break;
             case 32:
                data32 = (unsigned long *)data;
                resultObj = Tcl_NewListObj(count, NULL);
                for (i = 0; i < count; i++) {
                    Tcl_ListObjAppendElement(NULL, resultObj,
                      Tcl_NewIntObj(data32[i]));
                }
                Tcl_SetObjResult(interp, resultObj);
                break;
            }
            XFree(data);
            if (type != None) {
                typeStr = Tk_GetAtomName((Tk_Window)winPtr, type);
                Tcl_DictObjPut(NULL, options,
                  Tcl_NewStringObj("-propertytype", -1), 
                  Tcl_NewStringObj(typeStr, -1));
                Tcl_DictObjPut(NULL, options,
                  Tcl_NewStringObj("-propertyformat", -1), Tcl_NewIntObj(format));
                Tcl_SetReturnOptions(interp, options);
            }
        }
	return TCL_OK;
    }

    /* Properties starting with WM_ or _NET_WM_ are considered reserved */
    /* Those properties may only be changed using dedicated wm commands */
    if (strncmp(name, "WM_", 3) == 0 || strncmp(name, "_NET_WM_", 8) == 0) {
        Tcl_SetObjResult(interp, Tcl_ObjPrintf("changing reserved property "
          "\"%s\" is not allowed", name));
        return TCL_ERROR;
    }

    if (objc >= 6) {
        if (strcmp(Tcl_GetString(objv[5]), "None") == 0) {
            /* Delete the property */
            if (wmPtr->wrapperPtr != NULL) {
                XDeleteProperty(wmPtr->wrapperPtr->display,
                  wmPtr->wrapperPtr->window, property);
            }
            return TCL_OK;
        }
        type = Tk_InternAtom((Tk_Window)winPtr, Tcl_GetString(objv[5]));
    }

    if (objc >= 7) {
        if (Tcl_GetIntFromObj(interp, objv[6], &width) != TCL_OK) {
            return TCL_ERROR;
        }
    }

    if (width == 0) {
        width = type == XA_STRING || type == XA_UTF8_STRING ? 8 : 32;
    }

    if ((width != 8 && width != 16 && width != 32)
      || ((type == XA_ATOM || type == XA_BITMAP) && width != 32)
      || ((type == XA_STRING || type == XA_UTF8_STRING) && width != 8)) {
        Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid width: %d", width));
        return TCL_ERROR;
    }

    switch (width) {
     case 8:
        bytes = Tcl_GetByteArrayFromObj(objv[4], &length);
        if (length <= PROPMAXELEMENTS) {
            memcpy(data8, bytes, length);
        }
        break;
     case 16:
        data16 = (unsigned short *) data8;
        if (Tcl_ListObjGetElements(interp, objv[4],
          &length, &elements) != TCL_OK) return TCL_ERROR;
        if (length <= PROPMAXELEMENTS) {
            for (i = 0; i < length; i++) {
                if (Tcl_GetIntFromObj(interp, elements[i], &value) != TCL_OK) {
                    return TCL_ERROR;
                }
                data16[i] = value;
            }
        }
        break;
     case 32:
        data32 = (unsigned long *) data8;
        if (Tcl_ListObjGetElements(interp, objv[4],
          &length, &elements) != TCL_OK) return TCL_ERROR;
        if (length <= PROPMAXELEMENTS) {
            for (i = 0; i < length; i++) {
                if (Tcl_GetIntFromObj(NULL, elements[i], &value) != TCL_OK) {
                    data32[i] = Tk_InternAtom((Tk_Window)winPtr,
                      Tcl_GetString(elements[i]));
                } else {
                    data32[i] = value;
                }
            }
        }
    }

    if (length > PROPMAXELEMENTS) {
        Tcl_SetObjResult(interp, Tcl_NewStringObj("too many elements", -1));
        return TCL_ERROR;
    }

    /* Create the wrapper window, if necessary */
    if (wmPtr->wrapperPtr == NULL) CreateWrapper(wmPtr);
    /* Create or update the property */
    SetWindowProperty(wmPtr->wrapperPtr, name, type, width, data8, length);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * WmResizableCmd --
 *
 *	This function is invoked to process the "wm resizable" Tcl command.