Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch ctext Excluding Merge-Ins
This is equivalent to a diff from 676dda85eb to 44ccb9e7e7
2004-01-23
| ||
00:32 | ctext 3.1.3 Closed-Leaf check-in: 44ccb9e7e7 user: georgeps tags: ctext | |
2001-11-07
| ||
20:51 | initial import of tklib with cursor example module into CVS Closed-Leaf check-in: ec23b04ac2 user: hobbs tags: tklib-vendor-branch | |
1994-07-25
| ||
09:59 | Initial revision check-in: 6c8622ce26 user: jfontain tags: trunk | |
09:59 | initial empty check-in check-in: 676dda85eb user: root tags: trunk | |
Added modules/ctext/ChangeLog.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 3.1.3 - Thu Jan 22 14:51:08 GMT 2004 I changed the bindtags so that binding to the parent frame will cause the child $win.t to invoke those bindings. This means that you can create menus that popup on ButtonPress-3 without having to use bind.tree or a similar mechanism. Thank Jeff Hobbs for pointing this out. I fixed the destroy event handling, so that it will now not cleanup the widget when a temporary child of the widget is destroyed. 3.1.2 - Fri May 23 17:33:17 GMT 2003 I fixed ctext::deleteHighlighClass so that it will now delete regexp classes. I had to modify ctext::getHighlightClasses and ctext::addHighlightClassForRegexp to fix it. I've decided to keep the package provide at 3.1. 3.1.1 - Fri May 23 00:53:39 GMT 2003 I made some minor changes to configure instance handling, so that .t config will return the proper values. Alas I decided to add a TODO, because the values aren't quite like standard Tk; with the resource classes and all. 3.1 - Thu May 22 01:30:41 GMT 2003 I fixed some bugs on the configure instance handling. I added ctext::buildArgParseTable, which improves performance, because now the table is only generated once per widget. I improved cget to accept glob expressions, which also fixed a bug with strings like: cget -yscroll which didn't match an array element, but do match when passed to the real text widget. You can now pass strings like: .t config -flag and the value for -flag will be returned even if the flag is special to ctext. This took some engineering to get right. I fixed a bug in the test files that occured due to some fixes. Basically I'm using list now to construct the tagInfo for each highlight class. This caused problems, because I was previously using strings. The test files were using escapes to work around the quoting problem. They have been changed and now everything should work properly. You will need to lookout for this problem if you upgrade. I updated REGRESSION. The end result is a good release based on my testing. 3.1-alpha-5 - Thu May 15 00:39:10 GMT 2003 I fixed a minor bug in argument handling in the configure instance handler. 3.1-alpha-4 - Wed May 14 17:09:32 GMT 2003 I improved install.tcl by adding more information about auto_path. I fixed a bug with listbox selection in install.tcl (curselection wasn't used). I renamed ctext::getClasses to ctext::getHighlightClasses. I made some uplevel calls list based, so that if $win has a space in its path ctext will work correctly. I made the class creation procs all use list for storing items in the arrays. I modified ctext::getHighlightClasses to return a list in the format of: class [list items ...] I fixed a bug with ctext::addHighlightClassForRegexp. It wasn't storing the $re in the class array. This was new to the 3.x series. 3.1-alpha-2-3 - Tue May 13 19:30:51 GMT 2003 I have redone the configure instance handling. I added -linemap_select_fg and -linemap_select_bg. I have updated the README to reflect the new commands and options introduced in the 3.x series. I have removed the TODO file, because all tasks within it have been completed. I added an install.tcl script. It's very easy to use and passes all of my tests. I need to test with Malephiso, because there may be minor issues I haven't noticed. 3.1-alpha-1 - Mon May 12 23:12:18 GMT 2003 I've made many changes that have cleaned up the code. I have added -linemap_markable. I changed ctext::getAr to accept a suffix. I'm now using global variables with a __ctext prefix, because it is easier than using namespace variables. The _blink tag was renamed to __ctext_blink. I added ctext::deleteHighlightClass, which works with any of the 4 class creators. It needs more testing, but so far it passes all of my tests. I want to wait about a week or so and go over each line of code slowly. I've tried to engineer this well, but typos happen, so... I need to merge more of Andreas Sievers' changes and features. [At this point Andreas Sievers working on ASED submitted his 3.0 to me and I decided to create 3.1 which merges 2.7-alpha with his work.] 2.7-alpha - Fri May 2 13:08:48 GMT 2003 I have added -linemap_mark_command with an example in ctext_test_interactive.tcl I addec ctext::getAr which I'm using to store more state information about the widget for cget and configure. I modified cget and configure to use it, and they are now more useful. This is an alpha release because I haven't tested it much. I still need to spend some time and review the diffs. I'll probably get to that next week, and I'll test it with Malephiso (my editor). I should also update the README with information about -linemap_mark_command. 2.6.10 - Tue Apr 29 20:47:29 GMT 2003 I fixed a bug with -font handling in the instance command. You can now do: .t config -font and it will change the linemap font as well as the main text widget. I cleaned up argument handling in the constructor and instance commands. They now use concat and are simpler. I added ctext::event:Destroy which now takes care of removing an interp alias which was missing in previous releases. interp alias is now used rather than eval with a dummy proc for creating an instance command. $win now has a <FocusIn> binding that should fix a problem some of you may experience. You can now do: focus $win and it will act like: focus $win.t I removed uplevel n eval calls, which were pointless. I didn't realize when I wrote them that uplevel acts like eval. 2.6.9 - Mon Apr 28 16:17:13 GMT 2003 I fixed a minor focus issue by adding -takefocus 0 to the linemap creator. I also removed an uplevel #0 for interp alias, which wasn't needed. I removed the government clause in the LICENSE. I'm pondering a rewrite of Ctext (yet again) which will use SDynObject, and provide more features, but the thought "Why fix it if it isn't broken?" comes to mind. 2.6.8 - Mon Dec 2 18:24:49 GMT 2002 I fixed two bugs pointed out by Neil Madden. The initial creation of the widget failed when -linemap 0 was used. The virtual event <<Modified>> was not occuring. ---- I cleaned up several rough areas in the code. I cleaned up the code in the creation of the widget for -yscrollcommand and the linemap. I cleaned up the code in the configure instance command handler. ---- This release passes all of my tests with Tcl/Tk 8.3 and 8.4. To make debugging easier I have added ctext_test_interactive.tcl 2.6.7 - Fri Nov 22 16:39:41 GMT 2002 I fixed a bug with C comment highlighting. It wasn't updating the highlighting when the insertion was just one character. The problem was that the RE didn't match, because the previous char and next char were not used to decipher the match. This release was tested with Tcl/Tk 8.4 2.6.6 - Thu Aug 22 23:46:14 GMT 2002 I fixed a serious bug with ctext::matchPair and ctext::matchQuote. The problem was that in some cases the pattern )|}|] was causing an infinite loop when no other patterns matched. It was finding the same character over and over again. This is fixed now. I'm sorry to anyone that was bothered by this. I found it today with Malephiso while editing a test file. It basically locked up my editor. The long scripts and C code I've been editing in the past haven't had this problem, due to multiple characters matching. Please report BUGS. I need your help. 2.6.5 - Tue Aug 20 23:27:23 GMT 2002 I fixed a minor issue with <Destroy> handling. A catch was needed to prevent an error message, due to several <Destroy> events occuring in some cases. 2.6.4 - Tue Jul 23 19:29:49 MDT 2002 I fixed a minor bug with the linemap updating. I didn't notice that with a small number of lines it wasn't displaying the line numbers properly. I fixed a major flaw with 8.4 handling. The 8.4 text widget has some new features, and the edit instance command wasn't dealing with the requests properly. Now it should, but I haven't tested it a lot. 2.6.3 - Fri Jul 5 11:32:42 MDT 2002 I made improvements to ctext::matchPair that should improve the speed. I also fixed a bug that occured with the pattern { \}. I added an edit modified instance command. I'm not sure if it works like the Tk 8.4 version, but it should work well enough. I added edit modified tests to ctext_test.tcl I added -class Ctext to the parent frame. Those of you using .Xdefaults may want this. I updated the README for edit modified. It's about time for another study session of the code to fix any bugs or potential bugs. 2.6.2 - Mon Jul 1 09:31:39 MDT 2002 I fixed a bug with <Destroy> handling. I removed all calls to variable, and now use the fully qualified namespace name for variables. This makes the code more concise and cleaner. I improved the speed of ctext::addHighlightClassForSpecialChars by using foreach with [split $str ""]. I added a Destroy button to ctext_test.tcl. I removed the -font flags in the test files, so it will use what's in the X resources, or the default for Tk. I improved ctext::matchQuote:blink by doing if {$count & 1} rather than if {[expr {$count & 1}]} I need to remember that if is like expr. I fixed a Doh! in ctext::matchQuote. I was not thinking that the end pos is already known due to the switch in the instanceCmd. ctext::matchPair now works. Try typing a pattern of ( ) or [ ] or { } or ( ( ) ) and so on. It's really cool. Big thanks to Mac Cody for inspiring this. I didn't use any of his code for MatchPair but I looked at it to get a general idea. 2.6.1 - Thu Jun 27 10:55:54 MDT 2002 I added ctext::disableComments and ctext::enableComments. C comment highlighting is disabled by default now. I started merging the changes by Mac Cody into this release. I used some of his code for making quotes blink. I rewrote some of it to fit more with my ideals. I'll be merging more of his great ideas into Ctext in the future. I fixed a bug with the C comment highlighting. I found that \\ was causing problems, so the \\\\ RE addition and \\\\ check solves that. I replaced func_finder.tcl with a newer file that should work better. What I should probably do is write a minimal C parser for dealing with finding functions, or do another trick with the C preprocessor. I updated the README and ctext_test_c.tcl 2.6 - Mon Jun 24 09:39:24 MDT 2002 I radically modified ctext::comments to fix bugs with comments in quotes being highlighted and to improve speed. It is now much faster and simpler. I added -linemapfg and -linemapbg options. 2.5.2 - Sun May 19 09:36:16 MDT 2002 I made major changes to how the C commenting works. I made a serious mistake with the way that C comments were highlighted. I was invoking ctext::comments and there could be several after idle timers going that call it that were relying on a global array. Basically my state variables were getting clobbered. It took me a while to figure this out. Now I pass a [clock clicks] argument for each call and it creates the array if necessary and passes the clock clicks value in subsequent calls. The end result is that now several ctext::comments loops can be running at once and they don't clobber each other. 2.5.1 - Fri Mar 15 17:15:30 MST 2002 I have added ctext::update which allows you to update a cursor or progress dialog while Ctext highlights text. It works quite nicely in Malephiso. I updated the README to show the new change, and how to use it. I also fixed a minor error in the README. 2.5 - Sat Mar 2 23:59:07 MST 2002 I've fixed several critical bugs with deletion of text. I've improved the clarity of the code by adding ctext::instanceCmd. This also makes it so that theoretically you could overload ctext. The performance of deletion and insertion may be better due to my use of a timer for highlighting. 2.4.1 - Sat Feb 23 23:12:49 MST 2002 I fixed a bug with tag removal that occured when text was appended to an existing tag. The fix was to use the insert position minus one char in the call to ctext::findPreviousSpace. 2.4 - Tue Feb 5 16:27:46 MST 2002 The linemap will now update even if scrolling hasn't occured. I tried to get this working in previous releases, but had problems with display updates. Now I use "after 1" with it, so it works without blocking the GUI. The widget should now completely clean up after itself I hope. I made changes to the <Destroy> callback. Please let me know if it doesn't cleanup for you. 2.3.5 - Wed Jan 23 23:55:51 MST 2002 I fixed a minor bug that caused some text tags to be removed when they shouldn't be when deleting the first character of a line. if {[$self._t compare $start < $lineStart]} { set start $lineStart } 2.3.4 - Mon Jan 21 22:05:23 MST 2002 I added | and , to the not chars. This helps with C syntax highlighting. 2.3.3 - Mon Jan 14 23:06:39 MST 2002 I fixed a bug with C comment highlighting that occured when the state of the comment handler was not reset when it reached the end of the text widget. I also fixed a minor bug with tag removal in the delete handler. 2.3.2 - Thu Jan 10 19:48:20 MST 2002 I added " and ' to the not chars in the main highlighting engine. This makes it so that char start strings like $blah end at a " or '. So, for example with $blah" every thing would be highlighted like the variable. Now, it only highlights the $blah. 2.3.1 - Fri Jan 4 22:35:19 MST 2002 I fixed a minor bug with the C comment handling. I now have it working very fast for a while, and then it stops until being restarted when / or * is found/entered in the insert or delete widget instance commands. There is one bug I'm trying to track down where the highlighting stops for apparently no reason. It's probably good enough to use for production use in Malephiso, but as usual no warranty to you folks. 2.3 - Mon Dec 31 15:18:05 MST 2001 I have added C comment highlighting. It works properly but it flashes; which can be annoying. I'm going to work on this more later on. 2.2.8 - Mon Dec 31 04:18:57 MST 2001 I fixed some bugs with the delete instance command. 2.2.7 - Sun Dec 30 18:15:10 MST 2001 I made changes to ctext::highlight that have improved the speed. They should help a lot with very large files. 2.2.6 - Sun Dec 30 16:28:26 MST 2001 I improved the search expressions by adding -- to deal with - in any of the search strings. Using ctext in Malephiso has caused me to find so many bugs that I had no idea about over the past week or so. 2.2.5 - Sun Dec 30 11:10:38 MST 2001 I fixed a bug with findPreviousSpace and findNextSpace which should improve the speed of tag removal, because it will no longer remove char tags that it doesn't have to. 2.2.4 - Sun Dec 30 10:57:57 MST 2001 I fixed a bug with the highlighting that occured when the whitespace is entered between a highlighted word. I also fixed a bug with the linemap that occured when an empty line was pressed. 2.2.3 - Mon Dec 24 12:53:49 MST 2001 I added ; to the RE for not chars in the ctext::highlight proc. 2.2.2 - Sun Dec 23 14:37:26 MST 2001 I made a minor change to the highlighting RE, so that it handles things like [.widget cget -flag] Before this the -flag part wouldn't have been highlighted. I added ctext::clearHighlightClasses which takes only one argument; $win. 2.2.1 - Wed Dec 19 10:18:42 MST 2001 I fixed a bug that occured with some text widget commands, for example searching with -count. I had to use uplevel in the call to the master text widget. 2.2 - Wed Dec 19 06:18:08 MST 2001 I've fixed some bugs that occured if C functions were being highlighted. I changed addHighlightClassForSpecialChars so that it accepts a string of characters to match. All addHighlightClass commands now must have a window argument. The window argument makes it so that you can now have multiple languages highlighted in separate windows. I added ctext::addHighlightClassForRegexp (see the test files for examples). I'm going to write a script for finding all Tcl and Tk flags via an automated search through the man pages. This should hopefully help others with their custom editors that use ctext. 2.1.4 I fixed a few bugs. Widget destruction should now work properly. 2.1.3: Well, the diff between 2.1.2 and 2.1.3 is huge. To summarize I've replaced the list that stored selected linemap lines with an array, which has improved the performance. I've added error checking and done a bunch of cleanup. I've changed the indentation style. 2.1.2: LICENSE file added and licensing changed to BSD style. 2.1.1: replaced addHighlightClass array setting with a list (quoting hell fix) 2.1: added \r to the tests for the Mac added \r to the default regexp end of line for the Mac removed global and replaced with upvar #0 added ctext to the prefix of ToggledList new ctext_test2.tcl with two ctext widgets fixed the dos2unix script, so that {lf lf} -translation is used 2.0.2: fixed a bug with insert calling highlight improperly when pasting/inserting multiple lines wrote dos2unix to convert from NT's \r\n to \n so that Unix people aren't annoyed. update idletasks added to delete and insert instance commands 2.0.1: ctext_test.tcl removed extra ctext test window 2.0-a6: instance cget -linemap works added more documentation to Readme.txt 2.0-a5: removed hardcoded comment highlighting removed debug output and console show 2.0-a4: > 50% speedup during ctext::highlight due to a simpler regexp that uses not ([^ chars]+) instead. 2.0-a3: fixed bug with cut instance command added fastdelete and fastinsert instance commands instance config -linemap and -yscrollcommand work added highlight instance command added copy, cut, paste, and append selection instance commands 2.0-a2: proc ctext::addHighlightClassForSpecialChars proc ctext::addHighlightClassWithOnlyCharStart highlight function works merged delete from 1.1.1 and fixed a bug insert bug fix |
Added modules/ctext/LICENSE.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | This software is copyrighted by George Peter Staplin. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
Added modules/ctext/README.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | o Author George Peter Staplin See also: Thanks (below) o Licensing BSD style see the LICENSE file o Installation Ctext requires only one file named ctext.tcl. You can source this file or if you prefer to use "package require ctext" you can use the install.tcl script. The install script can be run like so: wish8.4 install.tcl If you are a developer I highly recommend that you study the Usage section below. If you need an example then see the test files (especialy ctext_test_interactive.tcl). o How it Works Ctext overloads the text widget and provides new commands, named highlight, copy, paste, cut, append, and edit. It also provides several commands that allow you to define classes. Each class corresponds to a tag in the widget. o Usage Ctext can be used like so: pack [ctext .t] .t fastinsert end $data .t highlight 1.0 end The copy, paste, and cut widget commands are frontends for tk_text*, but they don't require giving an argument for the text widget window. I have also addded an append command, which appends the current selection to the existing clipboard text. An edit modified command is available that keeps track of whether or not data in the widget has been modified. .t edit modified would return 0 if the data hasn't been modified. To set the value after inserting text you can use .t edit modified 0. It will automatically be set to 1 during insertion/deletion cut/paste etc. During insertion and deletion of text in the widget the tags and highlighting will be automatically updated, unless you specify -highlight 0 during creation or instance configuration of the widget. All of the flags that the text widget supports work. It also supports new flags. These new flags are: -linemap creates a line number list on the left of the widget. -linemapfg changes the foreground of the linemap. The default is the same color as the main text widget. -linemapbg changes the background of the linemap. The default is the same color as the main text widget. -linemap_select_fg changes the selected line foreground. The default is black. -linemap_select_bg changes the selected line background. The default is yellow. -linemap_mark_command calls a procedure or command with the path of the ctext window, the type which is either marked or unmarked, and finally the line number selected. The proc prototype is: proc linemark_cmd {win type line}. See also ctext_test_interactive.tcl -highlight takes a boolean value which defines whether or not to highlight text which is inserted or deleted. The default is 1. -linemap_markable takes a boolean value which specifies whether or not lines in the linemap are markable with the mouse. The default is 1. Four highlighting procedures are available for adding keywords. Each proc takes a class, color, keyword, and window argument. The highlight widget command will automatically use each class that you add with any of the three functions. If you want to change the font of a class or another attribute you can run a command like this: .t tag configure $className -font {Helvetica 16} Note that the tag is created when you add a class. Normal keywords: ctext::addHighlightClass .t class color [list string1 string2 ...] Strings that start with chars like $, for $var: ctext::addHighlightClassWithOnlyCharStart .t class color "\$" A series of characters in a string ctext:addHighlightClassForSpecialChars .t class color {[]{}} Comments, and other things that need regexp: ctext::addHighlightClassForRegexp .t class color {#\[^\n\]*} ctext::clearHighlightClasses clears all of the highlight classes from the widget specified. Example: ctext::clearHighlightClasses .t To get a list of classes defined for a widget do something like: ctext::getHighlightClasses .t To delete a highlight class do something like: ctext::deleteHighlightClass .t classNameToDelete You can update a cursor while ctext highlights a large file by overriding ctext::update. Simply source ctext.tcl then create your ctext::update proc, and it will be called by ctext. This allows you to have a progress dialog, or animated cursor. If you are using C and want C comments highlighted you can use ctext::enableComments. You can modify the colors of C comments by configuring the tag _cComment after enabling with the afformentioned command. The C comment highlighting is disabled by default. I have personally tested it with Tcl/Tk 8.4.4 in NetBSD. It should work with all Tcl platforms. Please send comments and bugs to [email protected] o Thanks Kevin Kenny, Neil Madden, Jeffrey Hobbs, Richard Suchenwirth, Johan Bengtsson, Mac Cody, G�nther, and Andreas Sievers. |
Added modules/ctext/REGRESSION.
> > > > | 1 2 3 4 | Due to changes between the 2.7 and 3.1 release you may need to remove escapes in your class patterns. This is due to my former inproper use of quotes, which I have now replaced with lists. The escaping is no longer necessary. Some fonts don't display a bitmap properly. The size of the bitmap seems to be the issue. This seems to be a bug with the text widget. |
Added modules/ctext/TODO.
> | 1 | Make the flags that ctext adds have Class and resource names. Also make .t config return those resource/class names. I suspect that I could do this by making each value for a flag a list, but this needs proper planning before I go coding in the unknown. |
Added modules/ctext/ctext.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # By George Peter Staplin # See also the README for a list of contributors # RCS: @(#) $Id: ctext.tcl,v 1.1.1.1 2004/01/23 00:32:16 georgeps Exp $ package require Tk package provide ctext 3.1 namespace eval ctext {} #win is used as a unique token to create arrays for each ctext instance proc ctext::getAr {win suffix name} { set arName __ctext[set win][set suffix] uplevel [list upvar #0 $arName $name] return $arName } proc ctext {win args} { if {[llength $args] & 1} { return -code error "invalid number of arguments given to ctext (uneven number after window) : $args" } frame $win -class Ctext set tmp [text .__ctextTemp] ctext::getAr $win config ar set ar(-fg) [$tmp cget -foreground] set ar(-bg) [$tmp cget -background] set ar(-font) [$tmp cget -font] set ar(-relief) [$tmp cget -relief] destroy $tmp set ar(-yscrollcommand) "" set ar(-linemap) 1 set ar(-linemapfg) $ar(-fg) set ar(-linemapbg) $ar(-bg) set ar(-linemap_mark_command) {} set ar(-linemap_markable) 1 set ar(-linemap_select_fg) black set ar(-linemap_select_bg) yellow set ar(-highlight) 1 set ar(win) $win set ar(modified) 0 set ar(ctextFlags) [list -yscrollcommand -linemap -linemapfg -linemapbg \ -font -linemap_mark_command -highlight -linemap_markable -linemap_select_fg \ -linemap_select_bg] array set ar $args foreach flag {foreground background} short {fg bg} { if {[info exists ar(-$flag)] == 1} { set ar(-$short) $ar(-$flag) unset ar(-$flag) } } #Now remove flags that will confuse text and those that need modification: foreach arg $ar(ctextFlags) { set loc [lsearch $args $arg] if {$loc >= 0} { set args [lreplace $args $loc [expr {$loc + 1}]] } } text $win.l -font $ar(-font) -width 1 -height 1 \ -relief $ar(-relief) -fg $ar(-linemapfg) -bg $ar(-linemapbg) -takefocus 0 set topWin [winfo toplevel $win] bindtags $win.l [list $win.l $topWin all] if {$ar(-linemap) == 1} { pack $win.l -side left -fill y } set args [concat $args [list -yscrollcommand [list ctext::event:yscroll $win $ar(-yscrollcommand)]]] #escape $win, because it could have a space pack [eval text \$win.t $args -font \$ar(-font)] -side right -fill both -expand 1 bind $win.t <Configure> [list ctext::linemapUpdate $win] bind $win.l <ButtonPress-1> [list ctext::linemapToggleMark $win %y] bind $win.t <KeyRelease-Return> [list ctext::linemapUpdate $win] rename $win __ctextJunk$win rename $win.t $win._t bind $win <Destroy> [list ctext::event:Destroy $win %W] bindtags $win.t [linsert [bindtags $win.t] 0 $win] interp alias {} $win {} ctext::instanceCmd $win interp alias {} $win.t {} $win #If the user wants C comments they should call ctext::enableComments ctext::disableComments $win ctext::modified $win 0 ctext::buildArgParseTable $win return $win } proc ctext::event:yscroll {win clientData args} { ctext::linemapUpdate $win if {$clientData == ""} { return } uplevel #0 $clientData $args } proc ctext::event:Destroy {win dWin} { if {![string equal $win $dWin]} { return } catch {rename $win {}} interp alias {} $win.t {} ctext::clearHighlightClasses $win array unset [ctext::getAr $win config ar] } #This stores the arg table within the config array for each instance. #It's used by the configure instance command. proc ctext::buildArgParseTable win { set argTable [list] lappend argTable any -linemap_mark_command { set configAr(-linemap_mark_command) $value break } lappend argTable {1 true yes} -linemap { pack $self.l -side left -fill y set configAr(-linemap) 1 break } lappend argTable {0 false no} -linemap { pack forget $self.l set configAr(-linemap) 0 break } lappend argTable any -yscrollcommand { set cmd [list $self._t config -yscrollcommand [list ctext::event:yscroll $self $value]] if {[catch $cmd res]} { return $res } set configAr(-yscrollcommand) $value break } lappend argTable any -linemapfg { if {[catch {winfo rgb $self $value} res]} { return -code error $res } $self.l config -fg $value set configAr(-linemapfg) $value break } lappend argTable any -linemapbg { if {[catch {winfo rgb $self $value} res]} { return -code error $res } $self.l config -bg $value set configAr(-linemapbg) $value break } lappend argTable any -font { if {[catch {$self.l config -font $value} res]} { return -code error $res } $self._t config -font $value set configAr(-font) $value break } lappend argTable {0 false no} -highlight { set configAr(-highlight) 0 break } lappend argTable {1 true yes} -highlight { set configAr(-highlight) 1 break } lappend argTable {0 false no} -linemap_markable { set configAr(-linemap_markable) 0 break } lappend argTable {1 true yes} -linemap_markable { set configAr(-linemap_markable) 1 break } lappend argTable any -linemap_select_fg { if {[catch {winfo rgb $self $value} res]} { return -code error $res } set configAr(-linemap_select_fg) $value $self.l tag configure lmark -foreground $value break } lappend argTable any -linemap_select_bg { if {[catch {winfo rgb $self $value} res]} { return -code error $res } set configAr(-linemap_select_bg) $value $self.l tag configure lmark -background $value break } ctext::getAr $win config ar set ar(argTable) $argTable } proc ctext::instanceCmd {self cmd args} { #slightly different than the RE used in ctext::comments set commentRE {\"|\\|'|/|\*} switch -glob -- $cmd { append { if {[catch {$self._t get sel.first sel.last} data] == 0} { clipboard append -displayof $self $data } } cget { set arg [lindex $args 0] ctext::getAr $self config configAr foreach flag $configAr(ctextFlags) { if {[string match ${arg}* $flag]} { return [set configAr($flag)] } } return [$self._t cget $arg] } conf* { ctext::getAr $self config configAr if {0 == [llength $args]} { set res [$self._t configure] set del [lsearch -glob $res -yscrollcommand*] set res [lreplace $res $del $del] foreach flag $configAr(ctextFlags) { lappend res [list $flag [set configAr($flag)]] } return $res } array set flags {} foreach flag $configAr(ctextFlags) { set loc [lsearch $args $flag] if {$loc < 0} { continue } if {[llength $args] <= ($loc + 1)} { #.t config -flag return [set configAr($flag)] } set flagArg [lindex $args [expr {$loc + 1}]] set args [lreplace $args $loc [expr {$loc + 1}]] set flags($flag) $flagArg } foreach {valueList flag cmd} $configAr(argTable) { if {[info exists flags($flag)]} { foreach valueToCheckFor $valueList { set value [set flags($flag)] if {[string equal "any" $valueToCheckFor]} $cmd \ elseif {[string equal $valueToCheckFor [set flags($flag)]]} $cmd } } } if {[llength $args]} { #we take care of configure without args at the top of this branch uplevel 1 [linsert $args 0 $self._t configure] } } copy { tk_textCopy $self } cut { if {[catch {$self.t get sel.first sel.last} data] == 0} { clipboard clear -displayof $self.t clipboard append -displayof $self.t $data $self delete [$self.t index sel.first] [$self.t index sel.last] ctext::modified $self 1 } } delete { #delete n.n ?n.n #first deal with delete n.n set argsLength [llength $args] if {$argsLength == 1} { set deletePos [lindex $args 0] set prevChar [$self._t get $deletePos] $self._t delete $deletePos set char [$self._t get $deletePos] set prevSpace [ctext::findPreviousSpace $self._t $deletePos] set nextSpace [ctext::findNextSpace $self._t $deletePos] set lineStart [$self._t index "$deletePos linestart"] set lineEnd [$self._t index "$deletePos + 1 chars lineend"] if {[string equal $prevChar "#"] || [string equal $char "#"]} { set removeStart $lineStart set removeEnd $lineEnd } else { set removeStart $prevSpace set removeEnd $nextSpace } foreach tag [$self._t tag names] { if {[string equal $tag "_cComment"] != 1} { $self._t tag remove $tag $removeStart $removeEnd } } set checkStr "$prevChar[set char]" if {[regexp $commentRE $checkStr]} { after idle [list ctext::comments $self] } ctext::highlight $self $lineStart $lineEnd ctext::linemapUpdate $self } elseif {$argsLength == 2} { #now deal with delete n.n ?n.n? set deleteStartPos [lindex $args 0] set deleteEndPos [lindex $args 1] set data [$self._t get $deleteStartPos $deleteEndPos] set lineStart [$self._t index "$deleteStartPos linestart"] set lineEnd [$self._t index "$deleteEndPos + 1 chars lineend"] eval \$self._t delete $args foreach tag [$self._t tag names] { if {[string equal $tag "_cComment"] != 1} { $self._t tag remove $tag $lineStart $lineEnd } } if {[regexp $commentRE $data]} { after idle [list ctext::comments $self] } ctext::highlight $self $lineStart $lineEnd if {[string first "\n" $data] >= 0} { ctext::linemapUpdate $self } } else { return -code error "invalid argument(s) sent to $self delete: $args" } ctext::modified $self 1 } fastdelete { eval \$self._t delete $args ctext::modified $self 1 ctext::linemapUpdate $self } fastinsert { eval \$self._t insert $args ctext::modified $self 1 ctext::linemapUpdate $self } highlight { ctext::highlight $self [lindex $args 0] [lindex $args 1] ctext::comments $self } insert { if {[llength $args] < 2} { return -code error "please use at least 2 arguments to $self insert" } set insertPos [lindex $args 0] set prevChar [$self._t get "$insertPos - 1 chars"] set nextChar [$self._t get $insertPos] set lineStart [$self._t index "$insertPos linestart"] set prevSpace [ctext::findPreviousSpace $self._t ${insertPos}-1c] set data [lindex $args 1] eval \$self._t insert $args set nextSpace [ctext::findNextSpace $self._t insert] set lineEnd [$self._t index "insert lineend"] if {[$self._t compare $prevSpace < $lineStart]} { set prevSpace $lineStart } if {[$self._t compare $nextSpace > $lineEnd]} { set nextSpace $lineEnd } foreach tag [$self._t tag names] { if {[string equal $tag "_cComment"] != 1} { $self._t tag remove $tag $prevSpace $nextSpace } } set REData $prevChar append REData $data append REData $nextChar if {[regexp $commentRE $REData]} { after idle [list ctext::comments $self] } after idle [list ctext::highlight $self $lineStart $lineEnd] switch -- $data { "\}" { ctext::matchPair $self "\\\{" "\\\}" "\\" } "\]" { ctext::matchPair $self "\\\[" "\\\]" "\\" } "\)" { ctext::matchPair $self "\\(" "\\)" "" } "\"" { ctext::matchQuote $self } } ctext::modified $self 1 ctext::linemapUpdate $self } paste { tk_textPaste $self ctext::modified $self 1 } edit { set subCmd [lindex $args 0] set argsLength [llength $args] ctext::getAr $self config ar if {"modified" == $subCmd} { if {$argsLength == 1} { return $ar(modified) } elseif {$argsLength == 2} { set value [lindex $args 1] set ar(modified) $value } else { return -code error "invalid arg(s) to $self edit modified: $args" } } else { #Tk 8.4 has other edit subcommands that I don't want to emulate. return [uplevel 1 [linsert $args 0 $self._t $cmd]] } } default { return [uplevel 1 [linsert $args 0 $self._t $cmd]] } } } proc ctext::tag:blink {win count} { if {$count & 1} { $win tag configure __ctext_blink -foreground [$win cget -bg] -background [$win cget -fg] } else { $win tag configure __ctext_blink -foreground [$win cget -fg] -background [$win cget -bg] } if {$count == 4} { $win tag delete __ctext_blink 1.0 end return } incr count after 50 [list ctext::tag:blink $win $count] } proc ctext::matchPair {win str1 str2 escape} { set prevChar [$win get "insert - 2 chars"] if {[string equal $prevChar $escape]} { #The char that we thought might be the end is actually escaped. return } set searchRE "[set str1]|[set str2]" set count 1 set pos [$win index "insert - 1 chars"] set endPair $pos set lastFound "" while 1 { set found [$win search -backwards -regexp $searchRE $pos] if {$found == "" || [$win compare $found > $pos]} { return } if {$lastFound != "" && [$win compare $found == $lastFound]} { #The search wrapped and found the previous search return } set lastFound $found set char [$win get $found] set prevChar [$win get "$found - 1 chars"] set pos $found if {[string equal $prevChar $escape]} { continue } elseif {[string equal $char [subst $str2]]} { incr count } elseif {[string equal $char [subst $str1]]} { incr count -1 if {$count == 0} { set startPair $found break } } else { #This shouldn't happen. I may in the future make it return -code error puts stderr "ctext seems to have encountered a bug in ctext::matchPair" return } } $win tag add __ctext_blink $startPair $win tag add __ctext_blink $endPair ctext::tag:blink $win 0 } proc ctext::matchQuote {win} { set endQuote [$win index insert] set start [$win index "insert - 1 chars"] if {[$win get "$start - 1 chars"] == "\\"} { #the quote really isn't the end return } set lastFound "" while 1 { set startQuote [$win search -backwards \" $start] if {$startQuote == "" || [$win compare $startQuote > $start]} { #The search found nothing or it wrapped. return } if {$lastFound != "" && [$win compare $lastFound == $startQuote]} { #We found the character we found before, so it wrapped. return } set lastFound $startQuote set start [$win index "$startQuote - 1 chars"] set prevChar [$win get $start] if {$prevChar == "\\"} { continue } break } if {[$win compare $endQuote == $startQuote]} { #probably just \" return } $win tag add __ctext_blink $startQuote $endQuote ctext::tag:blink $win 0 } proc ctext::enableComments {win} { $win tag configure _cComment -foreground khaki } proc ctext::disableComments {win} { catch {$win tag delete _cComment} } proc ctext::comments {win} { if {[catch {$win tag cget _cComment -foreground}]} { #C comments are disabled return } set startIndex 1.0 set commentRE {\\\\|\"|\\\"|\\'|'|/\*|\*/} set commentStart 0 set isQuote 0 set isSingleQuote 0 set isComment 0 $win tag remove _cComment 1.0 end while 1 { set index [$win search -count length -regexp $commentRE $startIndex end] if {$index == ""} { break } set endIndex [$win index "$index + $length chars"] set str [$win get $index $endIndex] set startIndex $endIndex if {$str == "\\\\"} { continue } elseif {$str == "\\\""} { continue } elseif {$str == "\\'"} { continue } elseif {$str == "\"" && $isComment == 0 && $isSingleQuote == 0} { if {$isQuote} { set isQuote 0 } else { set isQuote 1 } } elseif {$str == "'" && $isComment == 0 && $isQuote == 0} { if {$isSingleQuote} { set isSingleQuote 0 } else { set isSingleQuote 1 } } elseif {$str == "/*" && $isQuote == 0 && $isSingleQuote == 0} { if {$isComment} { #comment in comment break } else { set isComment 1 set commentStart $index } } elseif {$str == "*/" && $isQuote == 0 && $isSingleQuote == 0} { if {$isComment} { set isComment 0 $win tag add _cComment $commentStart $endIndex $win tag raise _cComment } else { #comment end without beginning break } } } } proc ctext::addHighlightClass {win class color keywords} { set ref [ctext::getAr $win highlight ar] foreach word $keywords { set ar($word) [list $class $color] } $win tag configure $class ctext::getAr $win classes classesAr set classesAr($class) [list $ref $keywords] } #For [ ] { } # etc. proc ctext::addHighlightClassForSpecialChars {win class color chars} { set charList [split $chars ""] set ref [ctext::getAr $win highlightSpecialChars ar] foreach char $charList { set ar($char) [list $class $color] } $win tag configure $class ctext::getAr $win classes classesAr set classesAr($class) [list $ref $charList] } proc ctext::addHighlightClassForRegexp {win class color re} { set ref [ctext::getAr $win highlightRegexp ar] set ar($class) [list $re $color] $win tag configure $class ctext::getAr $win classes classesAr set classesAr($class) [list $ref $class] } #For things like $blah proc ctext::addHighlightClassWithOnlyCharStart {win class color char} { set ref [ctext::getAr $win highlightCharStart ar] set ar($char) [list $class $color] $win tag configure $class ctext::getAr $win classes classesAr set classesAr($class) [list $ref $char] } proc ctext::deleteHighlightClass {win classToDelete} { ctext::getAr $win classes classesAr if {![info exists classesAr($classToDelete)]} { return -code error "$classToDelete doesn't exist" } foreach {ref keyList} [set classesAr($classToDelete)] { upvar #0 $ref refAr foreach key $keyList { if {![info exists refAr($key)]} { continue } unset refAr($key) } } unset classesAr($classToDelete) } proc ctext::getHighlightClasses win { ctext::getAr $win classes classesAr set res [list] foreach {class info} [array get classesAr] { lappend res $class } return $res } proc ctext::findNextChar {win index char} { set i [$win index "$index + 1 chars"] set lineend [$win index "$i lineend"] while 1 { set ch [$win get $i] if {[$win compare $i >= $lineend]} { return "" } if {$ch == $char} { return $i } set i [$win index "$i + 1 chars"] } } proc ctext::findNextSpace {win index} { set i [$win index $index] set lineStart [$win index "$i linestart"] set lineEnd [$win index "$i lineend"] #Sometimes the lineend fails (I don't know why), so add 1 and try again. if {[$win compare $lineEnd == $lineStart]} { set lineEnd [$win index "$i + 1 chars lineend"] } while {1} { set ch [$win get $i] if {[$win compare $i >= $lineEnd]} { set i $lineEnd break } if {[string is space $ch]} { break } set i [$win index "$i + 1 chars"] } return $i } proc ctext::findPreviousSpace {win index} { set i [$win index $index] set lineStart [$win index "$i linestart"] while {1} { set ch [$win get $i] if {[$win compare $i <= $lineStart]} { set i $lineStart break } if {[string is space $ch]} { break } set i [$win index "$i - 1 chars"] } return $i } proc ctext::clearHighlightClasses {win} { #no need to catch, because array unset doesn't complain #puts [array exists ::ctext::highlight$win] ctext::getAr $win highlight ar array unset ar ctext::getAr $win highlightSpecialChars ar array unset ar ctext::getAr $win highlightRegexp ar array unset ar ctext::getAr $win highlightCharStart ar array unset ar ctext::getAr $win classes ar array unset ar } #This is a proc designed to be overwritten by the user. #It can be used to update a cursor or animation while #the text is being highlighted. proc ctext::update {} { } proc ctext::highlight {win start end} { ctext::getAr $win config configAr if {!$configAr(-highlight)} { return } set si $start set twin "$win._t" #The number of times the loop has run. set numTimesLooped 0 set numUntilUpdate 600 ctext::getAr $win highlight highlightAr ctext::getAr $win highlightSpecialChars highlightSpecialCharsAr ctext::getAr $win highlightRegexp highlightRegexpAr ctext::getAr $win highlightCharStart highlightCharStartAr while 1 { set res [$twin search -count length -regexp -- {([^\s\(\{\[\}\]\)\.\t\n\r;\"'\|,]+)} $si $end] if {$res == ""} { break } set wordEnd [$twin index "$res + $length chars"] set word [$twin get $res $wordEnd] set firstOfWord [string index $word 0] if {[info exists highlightAr($word)] == 1} { set wordAttributes [set highlightAr($word)] foreach {tagClass color} $wordAttributes break $twin tag add $tagClass $res $wordEnd $twin tag configure $tagClass -foreground $color } elseif {[info exists highlightCharStartAr($firstOfWord)] == 1} { set wordAttributes [set highlightCharStartAr($firstOfWord)] foreach {tagClass color} $wordAttributes break $twin tag add $tagClass $res $wordEnd $twin tag configure $tagClass -foreground $color } set si $wordEnd incr numTimesLooped if {$numTimesLooped >= $numUntilUpdate} { ctext::update set numTimesLooped 0 } } foreach {ichar tagInfo} [array get highlightSpecialCharsAr] { set si $start foreach {tagClass color} $tagInfo break while 1 { set res [$twin search -- $ichar $si $end] if {"" == $res} { break } set wordEnd [$twin index "$res + 1 chars"] $twin tag add $tagClass $res $wordEnd $twin tag configure $tagClass -foreground $color set si $wordEnd incr numTimesLooped if {$numTimesLooped >= $numUntilUpdate} { ctext::update set numTimesLooped 0 } } } foreach {tagClass tagInfo} [array get highlightRegexpAr] { set si $start foreach {re color} $tagInfo break while 1 { set res [$twin search -count length -regexp -- $re $si $end] if {"" == $res} { break } set wordEnd [$twin index "$res + $length chars"] $twin tag add $tagClass $res $wordEnd $twin tag configure $tagClass -foreground $color set si $wordEnd incr numTimesLooped if {$numTimesLooped >= $numUntilUpdate} { ctext::update set numTimesLooped 0 } } } } proc ctext::linemapToggleMark {win y} { ctext::getAr $win config configAr if {!$configAr(-linemap_markable)} { return } set markChar [$win.l index @0,$y] set lineSelected [lindex [split $markChar .] 0] set line [$win.l get $lineSelected.0 $lineSelected.end] if {$line == ""} { return } ctext::getAr $win linemap linemapAr if {[info exists linemapAr($line)] == 1} { #It's already marked, so unmark it. array unset linemapAr $line ctext::linemapUpdate $win set type unmarked } else { #This means that the line isn't toggled, so toggle it. array set linemapAr [list $line {}] $win.l tag add lmark $markChar [$win.l index "$markChar lineend"] $win.l tag configure lmark -foreground $configAr(-linemap_select_fg) \ -background $configAr(-linemap_select_bg) set type marked } if {[string length $configAr(-linemap_mark_command)]} { uplevel #0 [linsert $configAr(-linemap_mark_command) end $win $type $line] } } #args is here because -yscrollcommand may call it proc ctext::linemapUpdate {win args} { if {[winfo exists $win.l] != 1} { return } set pixel 0 set lastLine {} set lineList [list] set fontMetrics [font metrics [$win._t cget -font]] set incrBy [expr {1 + ([lindex $fontMetrics 5] / 2)}] while {$pixel < [winfo height $win.l]} { set idx [$win._t index @0,$pixel] if {$idx != $lastLine} { set line [lindex [split $idx .] 0] set lastLine $idx $win.l config -width [string length $line] lappend lineList $line } incr pixel $incrBy } ctext::getAr $win linemap linemapAr $win.l delete 1.0 end set lastLine {} foreach line $lineList { if {$line == $lastLine} { $win.l insert end "\n" } else { if {[info exists linemapAr($line)]} { $win.l insert end "$line\n" lmark } else { $win.l insert end "$line\n" } } set lastLine $line } } proc ctext::modified {win value} { ctext::getAr $win config ar set ar(modified) $value event generate $win <<Modified>> return $value } |
Added modules/ctext/ctext_scroll_test.tcl.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | source ./ctext.tcl scrollbar .y -orient vertical -command {.t yview} ctext .t -xscrollcommand {.x set} -yscrollcommand {.y set} -wrap none scrollbar .x -orient horizontal -command {.t xview} grid .y -sticky ns grid .t -row 0 -column 1 grid .x -column 1 -sticky we |
Added modules/ctext/ctext_test.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/sh # the next line restarts using wish \ exec wish "$0" ${1+"$@"} #set tcl_traceExec 1 proc main {} { source ./ctext.tcl pack [frame .f] -fill both -expand 1 #Of course this could be cscrollbar instead, but it's not as common. pack [scrollbar .f.s -command {.f.t yview}] -side right -fill y #Dark colors pack [ctext .f.t -linemap 1 -bg black -fg white -insertbackground yellow \ -yscrollcommand {.f.s set}] -fill both -expand 1 ctext::addHighlightClass .f.t widgets purple [list obutton button label text frame toplevel \ cscrollbar scrollbar checkbutton canvas listbox menu menubar menubutton \ radiobutton scale entry message tk_chooseDir tk_getSaveFile \ tk_getOpenFile tk_chooseColor tk_optionMenu] ctext::addHighlightClass .f.t flags orange [list -text -command -yscrollcommand \ -xscrollcommand -background -foreground -fg -bg \ -highlightbackground -y -x -highlightcolor -relief -width \ -height -wrap -font -fill -side -outline -style -insertwidth \ -textvariable -activebackground -activeforeground -insertbackground \ -anchor -orient -troughcolor -nonewline -expand -type -message \ -title -offset -in -after -yscroll -xscroll -forward -regexp -count \ -exact -padx -ipadx -filetypes -all -from -to -label -value -variable \ -regexp -backwards -forwards -bd -pady -ipady -state -row -column \ -cursor -highlightcolors -linemap -menu -tearoff -displayof -cursor \ -underline -tags -tag] ctext::addHighlightClass .f.t stackControl red {proc uplevel namespace while for foreach if else} ctext::addHighlightClassWithOnlyCharStart .f.t vars mediumspringgreen "\$" ctext::addHighlightClass .f.t htmlText yellow "<b> </b> <i> </i>" ctext::addHighlightClass .f.t variable_funcs gold {set global variable unset} ctext::addHighlightClassForSpecialChars .f.t brackets green {[]{}} ctext::addHighlightClassForRegexp .f.t paths lightblue {\.[a-zA-Z0-9\_\-]+} ctext::addHighlightClassForRegexp .f.t comments khaki {#[^\n\r]*} #After overloading, insertion is a little slower with the #regular insert, so use fastinsert. #set fi [open Ctext_Bug_Crasher.tcl r] set fi [open long_test_script r] .f.t fastinsert end [read $fi] close $fi pack [frame .f1] -fill x pack [button .f1.append -text Append -command {.f.t append}] -side left pack [button .f1.cut -text Cut -command {.f.t cut}] -side left pack [button .f1.copy -text Copy -command {.f.t copy}] -side left pack [button .f1.paste -text Paste -command {.f.t paste}] -side left .f.t highlight 1.0 end pack [button .f1.test -text {Remove all Tags and Highlight} \ -command {puts [time { foreach tag [.f.t tag names] { .f.t tag remove $tag 1.0 end } update idletasks .f.t highlight 1.0 end }] } ] -side left pack [button .f1.fastdel -text {Fast Delete} -command {.f.t fastdelete 1.0 end}] -side left pack [frame .f2] -fill x pack [button .f2.test2 -text {Scrollbar Command {}} -command {.f.t config -yscrollcommand {}}] -side left pack [button .f2.cl -text {Clear Classes} -command {ctext::clearHighlightClasses .f.t}] -side left pack [button .f2.des -text Destroy -command {destroy .f.t}] -side left pack [button .f2.editModSet0 -text "Set Modified 0" -command {puts [.f.t edit modified 0]}] -side left pack [button .f2.editModGet -text "Print Modified" -command {puts [.f.t edit modified]}] -side left pack [button .f2.exit -text Exit -command exit] -side left puts [.f.t cget -linemap] puts [.f.t cget -linemapfg] puts [.f.t cget -linemapbg] puts [.f.t cget -bg] } main |
Added modules/ctext/ctext_test_c.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/sh # the next line restarts using wish \ exec wish "$0" ${1+"$@"} #use :: so I don't forget it's global #set ::tcl_traceExec 1 proc highlight:addClasses {win} { ctext::addHighlightClassForSpecialChars $win brackets green {[]} ctext::addHighlightClassForSpecialChars $win braces lawngreen {{}} ctext::addHighlightClassForSpecialChars $win parentheses palegreen {()} ctext::addHighlightClassForSpecialChars $win quotes "#c65e3c" {"'} ctext::addHighlightClass $win control red [list namespace while for if else do switch case] ctext::addHighlightClass $win types purple [list \ int char u_char u_int long double float typedef unsigned signed] ctext::addHighlightClass $win macros mediumslateblue [list \ #define #undef #if #ifdef #ifndef #endif #elseif #include #import #exclude] ctext::addHighlightClassForSpecialChars $win math cyan {+=*-/&^%!|<>} } proc main {} { source ./ctext.tcl pack [frame .f] -fill both -expand 1 #Of course this could be cscrollbar instead, but it's not as common. pack [scrollbar .f.s -command ".f.t yview"] -side right -fill y #Dark colors pack [ctext .f.t -linemap 1 \ -bg black -fg white -insertbackground yellow \ -yscrollcommand ".f.s set"] -fill both -expand 1 highlight:addClasses .f.t ctext::enableComments .f.t set fi [open test.c r] .f.t fastinsert end [read $fi] close $fi pack [button .append -text Append -command {.f.t append}] -side left pack [button .cut -text Cut -command {.f.t cut}] -side left pack [button .copy -text Copy -command {.f.t copy}] -side left pack [button .paste -text Paste -command {.f.t paste}] -side left .f.t highlight 1.0 end pack [button .test -text {Remove all Tags and Highlight} \ -command {puts [time { foreach tag [.f.t tag names] { .f.t tag remove $tag 1.0 end } update idletasks .f.t highlight 1.0 end }] } ] -side left pack [button .test2 -text {Scrollbar Command {}} -command {.f.t config -yscrollcommand {}}] -side left pack [button .cl -text {Clear Classes} \ -command {ctext::clearHighlightClasses .f.t}] -side left pack [button .exit -text Exit -command exit] -side left #pack [ctext .ct2 -linemap 1] -side bottom #update #console show #puts [.f.t cget -linemap] #puts [.f.t cget -bg] } main |
Added modules/ctext/ctext_test_interactive.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/sh # the next line restarts using wish \ exec wish "$0" ${1+"$@"} #set tcl_traceExec 1 proc linemap_mark_cmd {win type line} { puts "line $line was $type in $win" } proc main {} { source ./ctext.tcl pack [frame .f] -fill both -expand 1 #Of course this could be cscrollbar instead, but it's not as common. pack [scrollbar .f.s -command {.f.t yview}] -side right -fill y #Dark colors pack [ctext .f.t -bg black -fg white -insertbackground yellow \ -yscrollcommand {.f.s set} -linemap_mark_command linemap_mark_cmd] -fill both -expand 1 ctext::addHighlightClass .f.t widgets purple [list obutton button label text frame toplevel \ cscrollbar scrollbar checkbutton canvas listbox menu menubar menubutton \ radiobutton scale entry message tk_chooseDir tk_getSaveFile \ tk_getOpenFile tk_chooseColor tk_optionMenu] ctext::addHighlightClass .f.t flags orange [list -text -command -yscrollcommand \ -xscrollcommand -background -foreground -fg -bg \ -highlightbackground -y -x -highlightcolor -relief -width \ -height -wrap -font -fill -side -outline -style -insertwidth \ -textvariable -activebackground -activeforeground -insertbackground \ -anchor -orient -troughcolor -nonewline -expand -type -message \ -title -offset -in -after -yscroll -xscroll -forward -regexp -count \ -exact -padx -ipadx -filetypes -all -from -to -label -value -variable \ -regexp -backwards -forwards -bd -pady -ipady -state -row -column \ -cursor -highlightcolors -linemap -menu -tearoff -displayof -cursor \ -underline -tags -tag] ctext::addHighlightClass .f.t stackControl red {proc uplevel namespace while for foreach if else} ctext::addHighlightClassWithOnlyCharStart .f.t vars mediumspringgreen "\$" ctext::addHighlightClass .f.t htmlText yellow "<b> </b> <i> </i>" ctext::addHighlightClass .f.t variable_funcs gold {set global variable unset} ctext::addHighlightClassForSpecialChars .f.t brackets green {[]{}} ctext::addHighlightClassForRegexp .f.t paths lightblue {\.[a-zA-Z0-9\_\-]+} ctext::addHighlightClassForRegexp .f.t comments khaki {#[^\n\r]*} #After overloading, insertion is a little slower with the #regular insert, so use fastinsert. #set fi [open Ctext_Bug_Crasher.tcl r] set fi [open long_test_script r] .f.t fastinsert end [read $fi] close $fi pack [frame .f1] -fill x pack [button .f1.append -text Append -command {.f.t append}] -side left pack [button .f1.cut -text Cut -command {.f.t cut}] -side left pack [button .f1.copy -text Copy -command {.f.t copy}] -side left pack [button .f1.paste -text Paste -command {.f.t paste}] -side left .f.t highlight 1.0 end pack [button .f1.test -text {Remove all Tags and Highlight} \ -command {puts [time { foreach tag [.f.t tag names] { .f.t tag remove $tag 1.0 end } update idletasks .f.t highlight 1.0 end }] } ] -side left pack [button .f1.fastdel -text {Fast Delete} -command {.f.t fastdelete 1.0 end}] -side left pack [frame .f2] -fill x pack [button .f2.test2 -text {Scrollbar Command {}} -command {.f.t config -yscrollcommand {}}] -side left pack [button .f2.cl -text {Clear Classes} -command {ctext::clearHighlightClasses .f.t}] -side left pack [button .f2.des -text Destroy -command {destroy .f.t}] -side left pack [button .f2.editModSet0 -text "Set Modified 0" -command {puts [.f.t edit modified 0]}] -side left pack [button .f2.editModGet -text "Print Modified" -command {puts [.f.t edit modified]}] -side left pack [button .f2.exit -text Exit -command exit] -side left pack [entry .e] -side bottom -fill x .e insert end "ctext::deleteHighlightClass .f.t " bind .e <Return> {puts [eval [.e get]]} puts [.f.t cget -linemap] puts [.f.t cget -linemapfg] puts [.f.t cget -linemapbg] puts [.f.t cget -bg] } main |
Added modules/ctext/ctext_test_ws.tcl.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | source ./ctext.tcl pack [ctext {.t blah}] ctext::addHighlightClass {.t blah} c blue [list bat ball boot cat hat] ctext::addHighlightClass {.t blah} c2 red [list bozo bull bongo] {.t blah} highlight 1.0 end |
Added modules/ctext/function_finder.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/tclsh8.3 proc main {argc argv} { array set functions "" foreach f $argv { puts stderr "PROCESSING FILE $f" catch {exec cc -DNeedFunctionPrototypes -E $f} data #set functionList [regexp -all -inline {[a-zA-Z0-9_-]+[ \t\n\r]+([a-zA-Z0-9_-]+)[ \t\n\r]+\([ \t\n\r]*([^\)]+)[ \t\n\r]*\)[ \t\n\r]*;} $data] set functionList [regexp -all -inline {[a-zA-Z0-9_\-\*]+[ \t\n\r\*]+([a-zA-Z0-9_\-\*]+)[ \t\n\r]*\(([^\)]*)\)[ \t\n\r]*;} $data] set functionList [concat $functionList \ [regexp -all -inline {[a-zA-Z0-9_\-\*]+[ \t\n\r\*]+([a-zA-Z0-9_\-\*]+)[ \t\n\r]*_ANSI_ARGS_\(\(([^\)]*)\)\)[ \t\n\r]*;} $data]] #puts "FL $functionList" foreach {junk function args} $functionList { #puts "FUNC $function ARGS $args" set args [string map {"\n" "" "\r" "" "\t" " " "," ", "} $args] regsub -all {\s{2,}} $args " " args set functions($function) $args } } puts "array set ::functions \{" foreach function [lsort -dictionary [array names functions]] { if {"_" == [string index $function 0] || "_" == [string index $function end]} { continue } puts "\t$function [list [set functions($function)]]" } puts "\}" } proc sglob {pattern} { return [glob -nocomplain $pattern] } #main $argc /usr/local/include/tclDecls.h #return main $argc [concat [sglob /usr/include/*.h] [sglob /usr/include/*/*.h] \ [sglob /usr/local/include/*.h] [sglob /usr/local/include/*/*.h] \ [sglob /usr/X11R6/include/*.h] [sglob /usr/X11R6/include/*/*.h] \ [sglob /usr/X11R6/include/*/*/*.h] [sglob /usr/local/include/X11/*.h] \ [sglob /usr/local/include/X11/*/*.h]] |
Added modules/ctext/install.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #Run this with the wish (Tk shell) that you want to install for. #For example: $ wish8.4 install.tcl proc event.select.install.path win { set i [$win curselection] set ::installPath [$win get $i] } proc install {} { set idir [file join $::installPath ctext] file mkdir $idir file copy -force pkgIndex.tcl $idir file copy -force ctext.tcl $idir tk_messageBox -icon info -message "Successfully installed into $idir" \ -title {Install Successful} -type ok exit } proc main {} { option add *foreground black option add *background gray65 . config -bg gray65 wm title . {Ctext Installer} label .title -text {Welcome to the Ctext installer} -font {Helvetica 14} message .msgauto -aspect 300 -text {The auto_path directories are automatically searched by Tcl/Tk for packages. You may select a directory to install Ctext into, or type in a new directory. Your auto_path directories are:} set autoLen [llength $::auto_path] listbox .listauto -height $autoLen for {set i 0} {$i < $autoLen} {incr i} { .listauto insert end [lindex $::auto_path $i] } bind .listauto <<ListboxSelect>> [list event.select.install.path %W] label .lipath -text {Install Path:} set ::installPath [lindex $::auto_path end] entry .installPath -textvariable ::installPath frame .fcontrol frame .fcontrol.finst -relief sunken -bd 1 pack [button .fcontrol.finst.install -text Install -command install] -padx 4 -pady 4 button .fcontrol.cancel -text Cancel -command exit pack .fcontrol.finst -side left -padx 5 pack .fcontrol.cancel -side right -padx 5 pack .title -fill x pack .msgauto -anchor w pack .listauto -fill both -expand 1 pack .lipath -anchor w pack .installPath -fill x pack .fcontrol -pady 10 } main |
Added modules/ctext/long_test_script.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #By George Peter Staplin namespace eval cscrollbar { variable buttonPressed 0 variable lastX 0 variable lastY 0 variable up_xbm { #define up_width 18 #define up_height 12 static unsigned char up_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x0f, 0x00, 0xe0, 0x1f, 0x00, 0xf0, 0x3f, 0x00, 0xf8, 0x7f, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; } variable down_xbm { #define down_width 18 #define down_height 12 static char down_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xf8, 0x7f, 0x00, 0xf0, 0x3f, 0x00, 0xe0, 0x1f, 0x00, 0xc0, 0x0f, 0x00, 0x80, 0x07, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; } variable left_xbm { #define left_width 12 #define left_height 18 static char left_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0xc0, 0x01, 0xe0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xf8, 0x01, 0xf0, 0x01, 0xe0, 0x01, 0xc0, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }; } variable right_xbm { #define right_width 12 #define right_height 18 static char right_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00, 0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x03, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }; } } #This creates the scrollbar and an instance command for it. #cmdArgs represents the initial arguments. cmdArgs becomes smaller #gradually as options/flags are processed, and if it contains #anything else afterward an error is reported. proc cscrollbar {win args} { if {[expr {[llength $args] & 1}] != 0} { return -code error "Invalid number of arguments given to cscrollbar\ (uneven number): $args" } frame $win -class Cscrollbar upvar #0 _cscrollbar$win ar button .__temp set cmdArgs(-orient) vertical set cmdArgs(-bg) [option get $win background Color1] if {$cmdArgs(-bg) == ""} { set cmdArgs(-bg) [.__temp cget -bg] } set cmdArgs(-fg) [option get $win foreground Color1] if {$cmdArgs(-fg) == ""} { set cmdArgs(-fg) [.__temp cget -fg] } set cmdArgs(-slidercolor) [option get $win sliderColor Color1] if {$cmdArgs(-slidercolor) == ""} { set cmdArgs(-slidercolor) blue } set cmdArgs(-gradient1) [option get $win gradient1 Color1] if {$cmdArgs(-gradient1) == ""} { set cmdArgs(-gradient1) royalblue3 } set cmdArgs(-gradient2) [option get $win gradient2 Color1] if {$cmdArgs(-gradient2) == ""} { set cmdArgs(-gradient2) gray90 } set ar(sliderPressed) 0 destroy .__temp array set cmdArgs $args array set ar [array get cmdArgs] unset cmdArgs(-slidercolor) unset cmdArgs(-gradient1) unset cmdArgs(-gradient2) #synonym flags foreach long {background foreground} short {bg fg} { if {[info exists cmdArgs(-$long)] == 1} { set cmdArgs(-$short) $cmdArgs(-$long) unset cmdArgs(-long) } } if {$cmdArgs(-orient) == "vertical"} { cscrollbar::createVertical $win $cmdArgs(-bg) $cmdArgs(-fg) } elseif {$cmdArgs(-orient) == "horizontal"} { cscrollbar::createHorizontal $win $cmdArgs(-bg) $cmdArgs(-fg) } else { return -code error {Invalid -orient option -- use vertical or horizontal} } unset cmdArgs(-orient) unset cmdArgs(-fg) unset cmdArgs(-bg) if {[info exists cmdArgs(-command)] == 1} { bind $win.1 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$cmdArgs(-command)} -1 %W" bind $win.1 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$cmdArgs(-command)} -1 %W" bind $win.c <ButtonRelease-1> "cscrollbar::sliderNotPressed $win" bind $win.2 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$cmdArgs(-command)} 1 %W" bind $win.2 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$cmdArgs(-command)} 1 %W" bind $win.3 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$cmdArgs(-command)} -1 %W" bind $win.3 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$cmdArgs(-command)} -1 %W" bind $win.4 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$cmdArgs(-command)} 1 %W" bind $win.4 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$cmdArgs(-command)} 1 %W" bind $win <Configure> "after idle [list cscrollbar::updateView $win]" unset cmdArgs(-command) } if {[llength [array names cmdArgs]] != 0} { return -code error "Invalid argument sent to cscrollbar: [array get cmdArgs]" } rename $win _cscrollbarJunk$win bind $win <Destroy> "rename $win {};" proc $win {cmd args} "eval cscrollbar::instanceCmd $win \$cmd \$args" return $win } proc cscrollbar::updateView {win} { upvar #0 _cscrollbar$win ar if {[catch $ar(-command) res] && $res != ""} { $win set 0 1 } } proc cscrollbar::instanceCmd {self cmd args} { upvar #0 _cscrollbar$self ar switch -glob -- $cmd { cget { if {[info exists ar($args)] == 1} { return $ar($args) } else { return -code error "unknown argument(s) to cget: $args" } } conf* { if {[llength $args] == 0} { foreach name [array names ar -*] { append res "{$name $ar($name)} " } return $res } array set cmdArgs $args foreach long {background foreground} short {bg fg} { if {[info exists cmdArgs(-$long)] == 1} { set cmdArgs(-$short) $cmdArgs(-$long) unset cmdArgs(-$long) } } if {[info exists cmdArgs(-gradient1)] == 1} { set ar(-gradient1) $cmdArgs(-gradient1) event generate $self <Configure> } if {[info exists cmdArgs(-gradient2)] == 2} { set ar(-gradient2) $cmdArgs(-gradient2) event generate $self <Configure> } if {[info exists cmdArgs(-bg)] == 1} { set ar(-bg) $cmdArgs(-bg) $self.1 config -bg $ar(-bg) $self.c config -bg $ar(-bg) $self.2 config -bg $ar(-bg) if {$ar(-orient) == "vertical"} { $ar(upImage) config -background $ar(-bg) $ar(upDisabledImage) config -background $ar(-bg) $ar(downImage) config -background $ar(-bg) $ar(downDisabledImage) config -background $ar(-bg) } if {$ar(-orient) == "horizontal"} { $ar(leftImage) config -background $ar(-bg) $ar(leftDisabledImage) config -background $ar(-bg) $ar(rightImage) config -background $ar(-bg) $ar(rightDisabledImage) config -background $ar(-bg) } unset cmdArgs(-bg) } if {[info exists cmdArgs(-fg)] == 1} { set ar(-fg) $cmdArgs(-fg) $self.1 config -fg $ar(-fg) $self.2 config -fg $ar(-fg) $self.3 config -fg $ar(-fg) $self.4 config -fg $ar(-fg) if {$ar(-orient) == "vertical"} { $ar(upImage) config -foreground $ar(-fg) $ar(downImage) config -foreground $ar(-fg) } if {$ar(-orient) == "horizontal"} { $ar(leftImage) config -foreground $ar(-fg) $ar(rightImage) config -foreground $ar(-fg) } unset cmdArgs(-fg) } if {[info exists cmdArgs(-slidercolor)] == 1} { set ar(-slidercolor) $cmdArgs(-slidercolor) $self.c itemconfigure slider -fill $ar(-slidercolor) unset cmdArgs(-slidercolor) } if {[info exists cmdArgs(-command)] == 1} { set ar(-command) $cmdArgs(-command) bind $self.1 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$ar(-command)} -1 %W" bind $self.1 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$ar(-command)} -1 %W" bind $self.c <ButtonRelease-1> "cscrollbar::sliderNotPressed $self" bind $self.2 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$ar(-command)} 1 %W" bind $self.2 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$ar(-command)} 1 %W" bind $self.3 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$ar(-command)} -1 %W" bind $self.3 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$ar(-command)} -1 %W" bind $self.4 <ButtonPress-1> "set cscrollbar::buttonPressed 1; cscrollbar::moveUnit {$ar(-command)} 1 %W" bind $self.4 <ButtonRelease-1> "set cscrollbar::buttonPressed 0; cscrollbar::moveUnit {$ar(-command)} 1 %W" bind $self <Configure> " if {\[catch {$ar(-command)} res\] == 0 && \$res != \"\"} { $self set \$res } " unset cmdArgs(-command) } set res [llength [array names cmdArgs]] if {$res != 0} { return -code error "The following options were not recognized\ by cscrollbar: [array get cmdArgs]" } } set { set start [lindex $args 0] set end [lindex $args 1] #somehow this becomes a list when I don't want it to be. if {$end == ""} { set end [lindex $start 1] set start [lindex $start 0] } if {$end <= 0} { set end 1 } update idletasks if {$ar(-orient) == "vertical"} { if {$start == 0} { $self.1 config -image $ar(upDisabledImage) $self.3 config -image $ar(upDisabledImage) } else { $self.1 config -image $ar(upImage) $self.3 config -image $ar(upImage) } if {$end == 1} { $self.2 config -image $ar(downDisabledImage) $self.4 config -image $ar(downDisabledImage) } else { $self.2 config -image $ar(downImage) $self.4 config -image $ar(downImage) } if {$ar(sliderPressed) == 1} { return } #-2 is done for the border set areaHeight [expr {([winfo height $self.c] - 2)}] set startPos [expr {$start * $areaHeight}] set endPos [expr {$end * $areaHeight}] if {$endPos <= 0} { set endPos $areaHeight } $self.c coords slider 0 $startPos [winfo width $self.c] $endPos } if {$ar(-orient) == "horizontal"} { if {$start == 0} { $self.1 config -image $ar(leftDisabledImage) $self.3 config -image $ar(leftDisabledImage) } else { $self.1 config -image $ar(leftImage) $self.3 config -image $ar(leftImage) } if {$end == 1} { $self.2 config -image $ar(rightDisabledImage) $self.4 config -image $ar(rightDisabledImage) } else { $self.2 config -image $ar(rightImage) $self.4 config -image $ar(rightImage) } if {$ar(sliderPressed) == 1} { return } set areaWidth [expr {([winfo width $self.c] - 2)}] set startPos [expr {$start * $areaWidth}] set endPos [expr {$end * $areaWidth}] if {$endPos <= 0} { set endPos $areaWidth } $self.c coords slider $startPos 0 $endPos [winfo height $self.c] } } default { #puts "$cmd $args" } } } proc cscrollbar::createHorizontal {win bg fg} { upvar #0 _cscrollbar$win ar set bd 1 set ar(leftImage) [image create bitmap -data $cscrollbar::left_xbm \ -foreground $fg -background $bg] set ar(leftDisabledImage) [image create bitmap -data $cscrollbar::left_xbm \ -foreground gray50 -background $bg] set ar(rightImage) [image create bitmap -data $cscrollbar::right_xbm \ -foreground $fg -background $bg] set ar(rightDisabledImage) [image create bitmap -data $cscrollbar::right_xbm \ -foreground gray50 -background $bg] grid [label $win.1 -image $ar(leftDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 0 -column 0 -sticky w grid [label $win.2 -image $ar(rightDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 0 -column 1 -sticky w grid [canvas $win.c -relief flat -highlightthickness 0 \ -height [winfo reqheight $win.1] -width 10 -bg $bg] \ -row 0 -column 2 -sticky ew grid columnconfigure $win 2 -weight 1 grid [label $win.3 -image $ar(leftDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 0 -column 3 -sticky e grid [label $win.4 -image $ar(rightDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 0 -column 4 -sticky e cscrollbar::drawSlider $win 0 0 1 1 horizontal $win.c bind slider <B1-Motion> "cscrollbar::moveSlider $win horizontal %x" $win.c bind slider <ButtonPress-1> " set cscrollbar::lastX \[$win.c canvasx %x\] set cscrollbar::lastY \[$win.c canvasy %y\] " bind $win.c <Configure> "cscrollbar::drawBackground $win horizontal" } proc cscrollbar::createVertical {win bg fg} { upvar #0 _cscrollbar$win ar set bd 1 set ar(upImage) [image create bitmap -data $cscrollbar::up_xbm \ -foreground $fg -background $bg] set ar(upDisabledImage) [image create bitmap -data $cscrollbar::up_xbm \ -foreground gray50 -background $bg] set ar(downImage) [image create bitmap -data $cscrollbar::down_xbm \ -foreground $fg -background $bg] set ar(downDisabledImage) [image create bitmap -data $cscrollbar::down_xbm \ -foreground gray50 -background $bg] grid [label $win.1 -image $ar(upDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 0 -column 0 -sticky n grid [label $win.2 -image $ar(downDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 1 -column 0 -sticky n grid [canvas $win.c -relief flat -highlightthickness 0 \ -width [winfo reqwidth $win.1] -height 10 -bg $bg] \ -row 2 -column 0 -sticky ns grid rowconfigure $win 2 -weight 1 grid [label $win.3 -image $ar(upDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 3 -column 0 -sticky s grid [label $win.4 -image $ar(downDisabledImage) -relief raised -bg $bg -fg $fg -bd $bd] \ -row 4 -column 0 -sticky s cscrollbar::drawSlider $win 0 0 1 1 vertical $win.c bind slider <B1-Motion> "cscrollbar::moveSlider $win vertical %y" $win.c bind slider <ButtonPress-1> " set cscrollbar::lastX \[$win.c canvasx %x\] set cscrollbar::lastY \[$win.c canvasy %y\] " bind $win.c <Configure> "cscrollbar::drawBackground $win vertical" } #Based on Richard Suchenwirth's gradient code from one of his train #projects. proc cscrollbar::drawBackground {win type} { upvar #0 _cscrollbar$win ar set canv $win.c set x1 0 set y1 0 set x2 [expr {[winfo width $canv] + 8}] set y2 [expr {[winfo height $canv] + 8}] set c1 $ar(-gradient1) set c2 $ar(-gradient2) $canv delete background foreach {r1 g1 b1} [winfo rgb $canv $c1] break foreach {r2 g2 b2} [winfo rgb $canv $c2] break set redDiff [expr {$r2 - $r1}] set greenDiff [expr {$g2 - $g1}] set blueDiff [expr {$b2 - $b1}] switch $type { horizontal { set yDiff [expr {$y2 - $y1}] set steps [expr {int(abs($yDiff))}] if {$steps > 255} { set steps 255 } for {set i 2} {$i < $steps} {incr i} { set p [expr {double($i) / $steps}] set y [expr {$y1 + $yDiff * $p}] set r [expr {int($r1 + $redDiff * $p)}] set g [expr {int($g1 + $greenDiff * $p)}] set b [expr {int($b1 + $blueDiff * $p)}] set fillColor "#" foreach color {r g b} { set preColor [format "%2.2x" [set $color]] set color [format "%2.2s" $preColor] append fillColor $color } $canv create rectangle $x1 $y $x2 $y2 -outline {} -tag background \ -fill $fillColor } } vertical { set xDiff [expr {$x2 - $x1}] set steps [expr {int(abs($xDiff))}] if {$steps > 255} { set steps 255 } for {set i 2} {$i < $steps} {incr i} { set p [expr {double($i) / $steps}] set x [expr {$x1 + $xDiff * $p}] set r [expr {int($r1 + $redDiff * $p)}] set g [expr {int($g1 + $greenDiff * $p)}] set b [expr {int($b1 + $blueDiff * $p)}] set fillColor "#" foreach color {r g b} { set preColor [format "%2.2x" [set $color]] set color [format "%2.2s" $preColor] append fillColor $color } $canv create rectangle $x $y1 $x2 $y2 -outline {} -tag background \ -fill $fillColor } } default { return -code error "unknown direction \"$type\": must be one of horizontal or vertical" } } $win.c bind background <ButtonPress-1> "cscrollbar::scrollPages $win $type %x %y" $win.c lower background } proc cscrollbar::drawSlider {win x1 y1 x2 y2 type} { upvar #0 _cscrollbar$win ar #update idletasks $win.c delete slider if {$type == "vertical"} { set canvasWidth [winfo width $win.c] $win.c create rectangle 0 $y1 $canvasWidth $y2 \ -fill $ar(-slidercolor) -outline "" -tag slider -stipple gray50 return } if {$type == "horizontal"} { set canvasHeight [winfo height $win.c] $win.c create rectangle $x1 0 $x2 $canvasHeight \ -fill $ar(-slidercolor) -outline "" -tag slider -stipple gray50 return } } proc cscrollbar::moveSlider {win type position} { variable lastX variable lastY upvar #0 _cscrollbar$win ar if {$type == "vertical"} { #move the slider y values which are 1 and 3 in the coords list set sliderStartY [lindex [$win.c coords slider] 1] set sliderEndY [lindex [$win.c coords slider] 3] set sliderHeight [expr {$sliderEndY - $sliderStartY}] set areaHeight [expr {[winfo height $win.c] - 1}] set newY [expr {$position - $lastY}] set upBoundResult [expr {($sliderStartY + $newY) < 0}] set downBoundResult [expr {($sliderEndY + $newY) > $areaHeight}] if {$upBoundResult != 1 && $downBoundResult != 1} { $win.c move slider 0 $newY set lastY $position } elseif {$upBoundResult == 1} { set lastY [expr {$lastY - $sliderStartY}] $win.c move slider 0 [expr {-$sliderStartY}] } elseif {$downBoundResult == 1} { set amountToMove [expr {-$sliderStartY + ($areaHeight - $sliderHeight)}] set lastY [expr {$lastY + $amountToMove}] $win.c move slider 0 $amountToMove } if {[info exists ar(-command)] == 1} { set ar(sliderPressed) 1 eval $ar(-command) moveto [expr {$sliderStartY / $areaHeight}] } return } if {$type == "horizontal"} { #move the slider x values which are 0 and 2 in the coords list set sliderStartX [lindex [$win.c coords slider] 0] set sliderEndX [lindex [$win.c coords slider] 2] set sliderWidth [expr {$sliderEndX - $sliderStartX}] set areaWidth [expr {[winfo width $win.c] - 1}] set newX [expr {$position - $lastX}] set leftBoundResult [expr {($sliderStartX + $newX) < 0}] set rightBoundResult [expr {($sliderEndX + $newX) > $areaWidth}] if {$leftBoundResult != 1 && $rightBoundResult != 1} { $win.c move slider $newX 0 set lastX $position } elseif {$leftBoundResult == 1} { set lastX [expr {$lastX - $sliderStartX}] $win.c move slider [expr {-$sliderStartX}] 0 } elseif {$rightBoundResult == 1} { set amountToMove [expr {-$sliderStartX + ($areaWidth - $sliderWidth)}] set lastX [expr {$lastX + $amountToMove}] $win.c move slider $amountToMove 0 } if {[info exists ar(-command)] == 1} { set ar(sliderPressed) 1 eval $ar(-command) moveto [expr {$sliderStartX / $areaWidth}] } return } } #This moves the widget being scrolled a unit at a time. #It is invoked by the arrow buttons. The arrow buttons #are actually labels with bitmaps that have the -relief #change. proc cscrollbar::moveUnit {cmd unit self} { variable buttonPressed eval $cmd scroll $unit units $self config -relief sunken if {$buttonPressed == 1} { after 40 "cscrollbar::moveUnit {$cmd} $unit $self" } else { $self config -relief raised } } #This means that someone has pressed the trough/background #of the scrollbar, so we should scroll a page at a time. #Unlike Tk's scrollbar I don't continue scrolling while #the mouse is held down. Instead I chose to scroll once. #If the user wants it to continue they can press the mouse #again. proc cscrollbar::scrollPages {win type x y} { upvar #0 _cscrollbar$win ar if {$type == "horizontal"} { set sliderStartX [lindex [$win.c coords slider] 0] set sliderEndX [lindex [$win.c coords slider] 2] if {$x < $sliderStartX} { eval [concat $ar(-command) scroll -1 pages] } if {$x > $sliderEndX} { eval [concat $ar(-command) scroll 1 pages] } } if {$type == "vertical"} { set sliderStartY [lindex [$win.c coords slider] 1] set sliderEndY [lindex [$win.c coords slider] 3] if {$y < $sliderStartY} { eval [concat $ar(-command) scroll -1 pages] } if {$y > $sliderEndY} { eval [concat $ar(-command) scroll 1 pages] } } } proc cscrollbar::sliderNotPressed {win} { upvar #0 _cscrollbar$win ar set ar(sliderPressed) 0 if {[catch {$ar(-command)} res] == 0 && $res != ""} { $win set $res } } |
Added modules/ctext/pkgIndex.tcl.
> | 1 | package ifneeded ctext 3.1 [list source [file join $dir ctext.tcl]] |
Added modules/ctext/test.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 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 | /*The Panache Window Manager*/ /*By George Peter Staplin*/ /*Please read the LICENSE file included with the Panache distribution *for usage restrictions. */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #ifndef __STDC__ #include <malloc.h> #endif #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> #include <X11/Xatom.h> #include <X11/keysym.h> #include <X11/cursorfont.h> #include <tcl.h> #include "PanacheWindowList.h" /*Style I use if (returnFromFunc == 1) instead of if (returnFromFunc) I use if (returnFromFunc == 0) instead of if (!returnFromFunc) */ /*Automatic focus of new windows yes/no.*/ /*Automatic focus of transient windows yes/no.*/ #define PANACHE_DIRECTORY "Panache" #define CMD_ARGS (ClientData clientData, Tcl_Interp *interp, \ int objc, Tcl_Obj *CONST objv[]) Display *dis; XEvent report; Window root; Tcl_Interp *interp; int distance_from_edge = 0; Window mapped_window = None; int screen; Atom _XA_WM_STATE; Atom _XA_WM_PROTOCOLS; Atom _XA_WM_DELETE_WINDOW; Window workspace_manager; struct CList *keepAboveWindowList; unsigned long eventMask = (ResizeRedirectMask | PropertyChangeMask | \ EnterWindowMask | LeaveWindowMask | FocusChangeMask | KeyPressMask); #define winIdLength 14 /*#define FORK_ON_START*/ int PanacheGetWMState (Window win); void PanacheSelectInputForRootParented (Window win); void PanacheConfigureNormalWindow (Window win, unsigned long value_mask); char Panache_Init_script[] = { "if {[file exists $prefix/$panacheDirectory/Panache.tcl] != 1} {\n" " puts stderr {unable to open Panache.tcl Did you run make install?}\n" " puts stderr \"I looked in $prefix/$panacheDirectory\"\n" " exit -1\n" "}\n" "proc sendToPipe str {\n" " set str [string map {\"\n\" \"\" \"\r\" \"\"} $str]\n" " puts $::pipe $str\n" " flush $::pipe\n" "}\n" "proc getFromPipe {} {\n" " gets $::pipe line\n" " if {$line != \"\"} {\n" " set cmd [lindex $line 0]\n" " if {[llength $line] == 2} {\n" " $cmd [lindex $line 1]\n" " } else {\n" " eval $line\n" " }\n" " }\n" "}\n" "set ::pipe [open \"|$wishInterpreter $prefix/$panacheDirectory/Panache.tcl\" w+]\n" "fconfigure $::pipe -blocking 0\n" "\n"}; char *charMalloc (int size) { char *mem = NULL; mem = (char *) malloc ((sizeof (char)) * size); if (mem == NULL) { fprintf (stderr, "malloc failed to allocate memory This means that Panache \ and other applications could have problems if they continue running.\n\n \ exiting Panache now!"); exit (-1); } return mem; } void sendConfigureNotify (Window win, unsigned long value_mask, XWindowChanges *winChanges) { XEvent xe; XWindowAttributes wattr; if (XGetWindowAttributes (dis, win, &wattr) == 0) { return; } xe.type = ConfigureNotify; xe.xconfigure.type = ConfigureNotify; xe.xconfigure.event = win; xe.xconfigure.window = win; xe.xconfigure.x = (value_mask & CWX) ? winChanges->x : wattr.x; xe.xconfigure.y = (value_mask & CWY) ? winChanges->y : wattr.y; xe.xconfigure.width = (value_mask & CWWidth) ? winChanges->width : wattr.width; xe.xconfigure.height = (value_mask & CWHeight) ? winChanges->height : wattr.height; xe.xconfigure.border_width = 0; xe.xconfigure.above = None; xe.xconfigure.override_redirect = 0; XSendEvent (dis, win, 0, StructureNotifyMask, &xe); XFlush (dis); } void sendMapNotify (Window win) { XEvent mapNotify; mapNotify.type = MapNotify; mapNotify.xmap.type = MapNotify; mapNotify.xmap.window = win; mapNotify.xmap.display = dis; mapNotify.xmap.event = win; XSendEvent (dis, win, 0, StructureNotifyMask, &mapNotify); XFlush (dis); } int PanacheAddAllWindowsCmd CMD_ARGS { Window dummy; Window *children = NULL; unsigned int nchildren; unsigned int i; char *winId; char *transientForWinId; char str[] = "sendToPipe [list add [list $winTitle] $winId $winType $transientForWinId]"; Window twin; XSync (dis, 0); /*XGrabServer (dis);*/ if (XQueryTree (dis, root, &dummy, &dummy, &children, &nchildren) == 0) { fprintf (stderr, "Error querying the tree for the root window.\n"); } for (i = 0; i < nchildren; i++) { XTextProperty xtp; XWMHints *wmHints = XGetWMHints (dis, children[i]); XWindowAttributes wattr; xtp.value = NULL; if (wmHints == NULL) { continue; } if (wmHints->flags & IconWindowHint) { continue; } if (XGetWindowAttributes (dis, children[i], &wattr) == 0) { continue; } if (wattr.override_redirect == 1) { continue; } if (wmHints->flags & StateHint) { if (wmHints->initial_state & WithdrawnState) { continue; } else if (wattr.map_state == 0 && PanacheGetWMState (children[i]) == 0) { continue; } } XFree (wmHints); XGetWMName (dis, children[i], &xtp); winId = charMalloc (winIdLength); sprintf (winId, "%ld", children[i]); Tcl_SetVar (interp, "winTitle", (char *) xtp.value, 0); Tcl_SetVar (interp, "winId", winId, 0); if (XGetTransientForHint (dis, children[i], &twin) == 1) { Tcl_SetVar (interp, "winType", "transient", 0); transientForWinId = charMalloc (winIdLength); sprintf (transientForWinId, "%ld", twin); Tcl_SetVar (interp, "transientForWinId", transientForWinId, 0); free (transientForWinId); PanacheSelectInputForRootParented (children[i]); } else { Tcl_SetVar (interp, "winType", "normal", 0); Tcl_SetVar (interp, "transientForWinId", "", 0); /*Maybe I should compare the first char and then do strcmp?*/ if (xtp.value != NULL && strcmp ((char *)xtp.value, "___Panache_GUI") != 0) { PanacheConfigureNormalWindow (children[i], CWX|CWY|CWWidth|CWHeight); PanacheSelectInputForRootParented (children[i]); } } XFree (xtp.value); free (winId); if (Tcl_Eval (interp, str) != TCL_OK) { fprintf (stderr, "Error in PanacheAddAllWindowsCmd: %s\n", Tcl_GetStringResult (interp)); } } if (children != NULL) { XFree (children); } /*XUngrabServer (dis);*/ XSync (dis, 0); return TCL_OK; } void PanacheConfigureRequest (XConfigureRequestEvent *event) { XWindowChanges wc; Window twin; int maxWidth; int maxHeight; if (event->parent != root) { return; } #ifdef DEBUG fprintf (stderr, "ConfigureRequest win %ld\n", event->window); fprintf (stderr, "CWSibling %d\n", (event->value_mask & CWSibling) == 1); fprintf (stderr, "CWStackMode %d\n", (event->value_mask & CWStackMode) == 1); #endif maxWidth = (DisplayWidth (dis, screen) - distance_from_edge - 4); maxHeight = DisplayHeight (dis, screen); wc.border_width = 0; wc.sibling = None; wc.stack_mode = Above; if (event->window == workspace_manager) { wc.width = distance_from_edge; wc.height = maxHeight; wc.x = 0; wc.y = 0; XConfigureWindow(dis, event->window, CWX|CWY|CWWidth|CWHeight, &wc); sendConfigureNotify (event->window, CWX|CWY|CWWidth|CWHeight, &wc); return; } else { PanacheSelectInputForRootParented (event->window); } if (XGetTransientForHint (dis, event->window, &twin) == 1) { if (event->width > maxWidth) { wc.width = maxWidth; } else { wc.width = event->width; } wc.height = event->height; if (event->x < distance_from_edge) { wc.x = distance_from_edge; } else { wc.x = event->x; } wc.y = event->y; XConfigureWindow (dis, event->window, event->value_mask, &wc); sendConfigureNotify (event->window, event->value_mask, &wc); } else { PanacheConfigureNormalWindow (event->window, event->value_mask); } XFlush (dis); } /*This configures the window and sends a ConfigureNotify event. *It's designed for normal non-transient windows */ void PanacheConfigureNormalWindow ( Window win, unsigned long value_mask) { XWindowChanges wc; XSizeHints sizeHints; long ljunk = 0; int maxWidth = (DisplayWidth (dis, screen) - distance_from_edge - 4); int maxHeight = DisplayHeight (dis, screen); wc.border_width = 0; wc.sibling = None; wc.stack_mode = Above; wc.x = distance_from_edge; wc.y = 0; wc.width = maxWidth; wc.height = maxHeight; if (XGetWMNormalHints (dis, win, &sizeHints, &ljunk)) { if (sizeHints.flags & PMaxSize) { wc.width = (sizeHints.max_width > maxWidth) ? maxWidth : sizeHints.max_width; wc.height = (sizeHints.max_height > maxHeight) ? maxHeight : sizeHints.max_height; #ifdef DEBUG fprintf (stderr, "MaxSize %d %d\n", sizeHints.max_width, sizeHints.max_height); #endif } #ifdef DEBUG if (sizeHints.flags & PResizeInc) { fprintf (stderr, "PResizeInc\n"); fprintf (stderr, "incr %d %d\n", sizeHints.width_inc, sizeHints.height_inc); } if (sizeHints.flags & PAspect) { fprintf (stderr, "PAspect x %d\n", sizeHints.min_aspect.x); } #endif } XConfigureWindow (dis, win, value_mask, &wc); sendConfigureNotify (win, value_mask, &wc); } /*This appends windows that are not to be managed by *Panache to a list, and Panache will later on raise *them above other windows. */ void PanacheCreateNotify (XCreateWindowEvent *event) { if (event->override_redirect == 0 || event->parent != root) { return; } CListAppend (keepAboveWindowList, event->window); } /*X has told Panache that a DestroyNotify event occured *to a child of the root window, so Panache removes the *window from the window list. */ void PanacheDestroyNotify (XDestroyWindowEvent *event) { Window win; char *winId; char str[] = "sendToPipe [list remove $winId]"; win = event->window; winId = charMalloc (winIdLength); sprintf (winId, "%ld", win); Tcl_SetVar (interp, "winId", winId, 0); free (winId); #ifdef DEBUG fprintf (stderr, "DestroyNotify\n"); #endif CListRemove (keepAboveWindowList, event->window); /*Tell Panache_GUI to remove the window*/ if (Tcl_Eval (interp, str) != TCL_OK) { fprintf (stderr, "Tcl_Eval error in PanacheDestroyNotify %s\n", Tcl_GetStringResult (interp)); } } /*Panache_GUI calls this to send WM_DELETE_WINDOW or *invoke XKillClient (if the window doesn't support *WM_DELETE_WINDOW). We can't use XKillClient on all *windows, because if the application has multiple *toplevel windows sending XKillClient would destroy *them all. */ int PanacheDestroyCmd CMD_ARGS { XClientMessageEvent ev; Window win; Atom *wmProtocols = NULL; Atom *protocol; int i; int numAtoms; int handlesWM_DELETE_WINDOW = 0; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); if (XGetWMProtocols (dis, win, &wmProtocols, &numAtoms) == 1) { for (i = 0, protocol = wmProtocols; i < numAtoms; i++, protocol++) { if (*protocol == (Atom)_XA_WM_DELETE_WINDOW) { handlesWM_DELETE_WINDOW = 1; } } if (wmProtocols) { XFree (wmProtocols); } } if (handlesWM_DELETE_WINDOW == 1) { ev.type = ClientMessage; ev.window = win; ev.message_type = _XA_WM_PROTOCOLS; ev.format = 32; ev.data.l[0] = _XA_WM_DELETE_WINDOW; ev.data.l[1] = CurrentTime; XSendEvent (dis, win, 0, 0L, (XEvent *) &ev); } else { XKillClient (dis, win); } XFlush (dis); return TCL_OK; } int PanacheDFECmd CMD_ARGS { Tcl_GetIntFromObj (interp, objv[1], &distance_from_edge); return TCL_OK; } /*Panache_GUI sends focus $winId to get here.*/ int PanacheFocusCmd CMD_ARGS { Window win; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); if (XSetInputFocus (dis, win, RevertToParent, CurrentTime) != 1) { fprintf (stderr, "XSetInputFocus failure within PanacheFocusCmd()"); } XFlush (dis); return TCL_OK; } int PanacheGetWMState (Window win) { int returnValue = 0; Atom type; int ijunk; unsigned long ljunk; unsigned long *state = NULL; XGetWindowProperty ( dis, win, _XA_WM_STATE, 0L, 1L, 0, _XA_WM_STATE, &type, &ijunk, &ljunk, &ljunk, (unsigned char **) &state ); if (type == _XA_WM_STATE) { returnValue = (int) *state; } else { /*Don't know what to do*/ returnValue = 0; } if (state != NULL) { XFree (state); } return returnValue; } /*A window to keep above has the override_redirect *attribute set to 1. */ void PanacheRaiseKeepAboveWindows () { Window win; CListRewind (keepAboveWindowList); while ((win = CListGet (keepAboveWindowList)) != NULL) { XRaiseWindow (dis, win); } XFlush (dis); } void PanacheRecursivelyGrabKey (Window win, int keycode) { Window dummy; Window *children = NULL; unsigned int nchildren; int i; if (XQueryTree (dis, win, &dummy, &dummy, &children, &nchildren) == 0) { return; } for (i = 0; i < nchildren; i++) { PanacheRecursivelyGrabKey (children[i], keycode); XGrabKey (dis, keycode, Mod1Mask, win, 1, GrabModeAsync, GrabModeSync); } if (children != NULL) { XFree (children); } } int PanacheReparentCmd CMD_ARGS { Window newParent; Window win; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); Tcl_GetLongFromObj (interp, objv[2], (long *) &newParent); XReparentWindow (dis, win, newParent, 0, 20); return TCL_OK; } void PanacheSelectInputForRootParented (Window win) { XSelectInput (dis, win, eventMask); } void PanacheSetWMState (Window win, int state) { unsigned long data[2]; data[0] = state; data[1] = None; XChangeProperty (dis, win, _XA_WM_STATE, _XA_WM_STATE, 32, PropModeReplace, (unsigned char *) data, 2 ); XSync (dis, 0); } int PanacheTransientCmd CMD_ARGS { Window parent; Window win; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); Tcl_GetLongFromObj (interp, objv[2], (long *) &parent); XSetTransientForHint (dis, win, parent); return TCL_OK; } /*This sends a string to Panache_GUI with info about the window, *such as its title and window id. This information is processed *within Panache_GUI and if desired PanacheMapCmd will map the *window. */ void PanacheMapRequest (XMapRequestEvent *event) { char *winId; char *transientForWinId; XTextProperty xtp; char str[] = "sendToPipe [list add [list $winTitle] $winId $winType $transientForWinId]"; Window twin; if (event->window == NULL) { return; } /*This makes the state iconic, so that if the user presses *restart before mapping the window, the window will show up. */ PanacheSetWMState (event->window, IconicState); xtp.value = NULL; XGetWMName (dis, event->window, &xtp); winId = charMalloc (winIdLength); sprintf (winId, "%ld", event->window); PanacheSelectInputForRootParented (event->window); Tcl_SetVar (interp, "winTitle", (char *) xtp.value, 0); Tcl_SetVar (interp, "winId", winId, 0); if (XGetTransientForHint (dis, event->window, &twin) == 1) { Tcl_SetVar (interp, "winType", "transient", 0); transientForWinId = charMalloc (winIdLength); sprintf (transientForWinId, "%ld", twin); Tcl_SetVar (interp, "transientForWinId", transientForWinId, 0); free (transientForWinId); } else { Tcl_SetVar (interp, "winType", "normal", 0); Tcl_SetVar (interp, "transientForWinId", "", 0); } XFree (xtp.value); free (winId); if (Tcl_Eval (interp, str) != TCL_OK) { fprintf (stderr, "Error in PanacheMapRequest: %s\n", Tcl_GetStringResult (interp)); } } /*This maps a window. It may be called after PanacheMapRequest by *Panache_GUI. This is also called when a window is over another *window and the user selects the button for the window to display *which causes this function to raise the window. */ int PanacheMapCmd CMD_ARGS { Window win; Window twin; XWindowAttributes winAttrib; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); PanacheSelectInputForRootParented (win); /*XGrabKey (dis, XK_Tab, Mod1Mask, win, 1, GrabModeAsync, GrabModeAsync);*/ /*PanacheRecursivelyGrabKey (win, XK_Tab);*/ XGetWindowAttributes (dis, win, &winAttrib); if (winAttrib.x < distance_from_edge) { winAttrib.x = distance_from_edge; if (winAttrib.y < 0) { winAttrib.y = 0; } XMoveWindow (dis, win, winAttrib.x, winAttrib.y); } if (XGetTransientForHint (dis, win, &twin) == 1) { PanacheSetWMState (win, NormalState); XMapRaised (dis, win); sendMapNotify (win); mapped_window = win; PanacheRaiseKeepAboveWindows (); return TCL_OK; } if ((PanacheGetWMState (win)) == 1) { XRaiseWindow (dis, win); PanacheRaiseKeepAboveWindows (); return TCL_OK; } /*If we are here the window hasn't had its size set, or *the WM_STATE was not 1. */ PanacheSetWMState (win, NormalState); /*I've found that some applications get upset if you sent *a ConfigureNotify before the MapNotify, when they are *expecting the MapNotify to be eminent. */ XMapRaised (dis, win); sendMapNotify (win); PanacheConfigureNormalWindow (win, CWX|CWY|CWWidth|CWHeight); mapped_window = win; PanacheRaiseKeepAboveWindows (); return TCL_OK; } int PanacheMapWorkspaceCmd CMD_ARGS { XWindowChanges wc; Window win; Tcl_GetLongFromObj (interp, objv[1], (long *) &win); workspace_manager = win; PanacheSetWMState (win, NormalState); wc.x = 0; wc.y = 0; wc.width = distance_from_edge; wc.height = DisplayHeight (dis, screen); XConfigureWindow(dis, win, CWX|CWY|CWWidth|CWHeight, &wc); sendConfigureNotify (win, CWX|CWY|CWWidth|CWHeight, &wc); XMapWindow (dis, win); sendMapNotify (win); mapped_window = win; XFlush (dis); return TCL_OK; } int PanacheMoveCmd CMD_ARGS { XEvent event; unsigned int buttonPressed; Window wjunk; int ijunk; Cursor handCursor; Window win; int oldX; int oldY; int x; int y; int internalX; int internalY; unsigned int maskReturn; int continueEventLoop = 1; XWindowAttributes winAttr; handCursor = XCreateFontCursor (dis, XC_hand2); XGrabPointer (dis, root, 1, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | \ PointerMotionHintMask, GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime ); /*Wait until the user has selected the window to move.*/ XMaskEvent (dis, ButtonPressMask, &event); /*The button being held down while dragging the window.*/ buttonPressed = event.xbutton.button; /*fprintf (stderr, "ButtonPressed %d\n", buttonPressed);*/ XQueryPointer (dis, root, &wjunk, &win, &oldX, &oldY, &internalX, &internalY, &maskReturn ); if (win == workspace_manager) { XUngrabPointer (dis, CurrentTime); XFreeCursor (dis, handCursor); XSync (dis, 0); return TCL_OK; } XGetWindowAttributes (dis, win, &winAttr); while (continueEventLoop == 1) { XNextEvent (dis, &event); switch (event.type) { case ButtonRelease: { if (event.xbutton.button == buttonPressed) { continueEventLoop = 0; } } break; case MotionNotify: { XWindowChanges wc; int newX; int newY; while (XCheckTypedEvent (dis, MotionNotify, &event)); XQueryPointer (dis, root, &wjunk, &wjunk, &x, &y, &ijunk, &ijunk, &maskReturn ); newX = x - oldX + winAttr.x; newY = y - oldY + winAttr.y; if (newX < distance_from_edge) { if (winAttr.override_redirect == 1) { XMoveWindow (dis, win, distance_from_edge, newY); } else { wc.x = distance_from_edge; wc.y = newY; XConfigureWindow (dis, win, CWX | CWY, &wc); sendConfigureNotify (win, CWX | CWY, &wc); } continue; } if (winAttr.override_redirect == 1) { XMoveWindow (dis, win, newX, newY); } else { wc.x = newX; wc.y = newY; XConfigureWindow (dis, win, CWX | CWY, &wc); sendConfigureNotify (win, CWX | CWY, &wc); } } break; } } /*fprintf (stderr, "win is %ld\n", win);*/ XUngrabPointer (dis, CurrentTime); XFreeCursor (dis, handCursor); XSync (dis, 0); return TCL_OK; } XErrorHandler PanacheErrorHandler (Display *dis, XErrorEvent *event) { /*I've discovered that errors are frequently timing problems. Maybe XSync would help in some areas. Most errors are not fatal. */ return 0; } int main() { fd_set readfds; int nfds; int xFd; int pipeFd; int inputPipeFd; ClientData data; int fdsTcl; dis = XOpenDisplay (NULL); screen = DefaultScreen (dis); root = RootWindow (dis, screen); interp = Tcl_CreateInterp (); XSetErrorHandler ((XErrorHandler) PanacheErrorHandler); _XA_WM_STATE = XInternAtom (dis, "WM_STATE", 0); _XA_WM_PROTOCOLS = XInternAtom (dis, "WM_PROTOCOLS", 0); _XA_WM_DELETE_WINDOW = XInternAtom (dis, "WM_DELETE_WINDOW", 0); keepAboveWindowList = CListInit (); #ifdef FORK_ON_START { int res; res = fork(); if (res == -1) { fprintf (stderr, "Unable to fork process."); return 1; } if (res != 0) { exit (0); } } #endif if (Tcl_Init (interp) != TCL_OK) { printf ("Tcl_Init error\n"); exit (-1); } #define CREATE_CMD(cmdName,func) Tcl_CreateObjCommand (interp, \ cmdName, func, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL) CREATE_CMD ("map_workspace", PanacheMapWorkspaceCmd); CREATE_CMD ("distance_from_edge", PanacheDFECmd); CREATE_CMD ("map", PanacheMapCmd); CREATE_CMD ("destroy", PanacheDestroyCmd); CREATE_CMD ("add_all_windows", PanacheAddAllWindowsCmd); CREATE_CMD ("focus", PanacheFocusCmd); CREATE_CMD ("transient", PanacheTransientCmd); CREATE_CMD ("reparent", PanacheReparentCmd); CREATE_CMD ("move", PanacheMoveCmd); Tcl_SetVar (interp, "wishInterpreter", WISH_INTERPRETER, 0); Tcl_SetVar (interp, "prefix", PREFIX, 0); Tcl_SetVar (interp, "panacheDirectory", PANACHE_DIRECTORY, 0); if (Tcl_Eval (interp, Panache_Init_script) != TCL_OK) { fprintf (stderr, "Error while evaluating Panache_Init_script within main()%s\n", Tcl_GetStringResult (interp)); exit (-1); } XSelectInput (dis, root, LeaveWindowMask | EnterWindowMask| \ PropertyChangeMask | SubstructureRedirectMask | \ SubstructureNotifyMask | KeyPressMask | KeyReleaseMask | \ ResizeRedirectMask | FocusChangeMask ); xFd = ConnectionNumber (dis); Tcl_GetChannelHandle (Tcl_GetChannel (interp, Tcl_GetVar (interp, "pipe", NULL), NULL), TCL_WRITABLE, &data); pipeFd = (int) data; /*fprintf (stderr, "pipeFd %d", pipeFd);*/ Tcl_GetChannelHandle (Tcl_GetChannel (interp, Tcl_GetVar (interp, "pipe", NULL), NULL), TCL_READABLE, &data); inputPipeFd = (int) data; XFlush(dis); for (;;) { FD_ZERO (&readfds); FD_SET (xFd, &readfds); FD_SET (pipeFd, &readfds); FD_SET (inputPipeFd, &readfds); fdsTcl = (pipeFd > inputPipeFd) ? pipeFd : inputPipeFd; nfds = (xFd > fdsTcl) ? xFd + 1: fdsTcl + 1; select (nfds, &readfds, NULL, NULL, NULL); if (FD_ISSET (inputPipeFd, &readfds) != 0) { if (Tcl_Eval (interp, "getFromPipe") != TCL_OK) { fprintf (stderr, "getFromPipe error %s\n", Tcl_GetStringResult (interp)); } } if (FD_ISSET (pipeFd, &readfds) != 0) { while (Tcl_DoOneEvent (TCL_DONT_WAIT)); } if (FD_ISSET (xFd, &readfds) == 0) { continue; } while (XPending (dis) > 0) { XNextEvent (dis, &report); /*fprintf (stderr, "type %d\n", report.type);*/ switch (report.type) { case ConfigureNotify: /*fprintf (stderr, "ConfigureNotify \n");*/ break; case CreateNotify: PanacheCreateNotify (&report.xcreatewindow); break; case ConfigureRequest: PanacheConfigureRequest (&report.xconfigurerequest); break; case DestroyNotify: PanacheDestroyNotify (&report.xdestroywindow); break; case EnterNotify: { Window win = report.xcrossing.window; char *winId = NULL; char cmd[] = "sendToPipe [list activateWindow $winId]"; winId = charMalloc (winIdLength); sprintf (winId, "%ld", win); Tcl_SetVar (interp, "winId", winId, 0); free (winId); if (Tcl_Eval (interp, cmd) != TCL_OK) { fprintf (stderr, "Error evaluating cmd in EnterNotify within main() %s\n", Tcl_GetStringResult (interp)); } } break; case FocusIn: break; case KeyPress: { char cmd[] = "sendToPipe next"; if (XLookupKeysym (&report.xkey, 0) == XK_Tab && (report.xkey.state & Mod1Mask)) { fprintf (stderr, "alt tab win %ld\n", report.xkey.window); if (Tcl_Eval (interp, cmd) != TCL_OK) { fprintf (stderr, "Error evaluating cmd in KeyPress within main() %s\n", Tcl_GetStringResult (interp)); } } else { /*Send XK_Tab*/ } /* fprintf (stderr, "1 %d \n", report.xkey.state == Mod1Mask); fprintf (stderr, "2 %d \n", report.xkey.state == Mod2Mask); fprintf (stderr, "3 %d \n", report.xkey.state == Mod3Mask); fprintf (stderr, "4 %d \n", report.xkey.state == Mod4Mask); fprintf (stderr, "5 %d \n", report.xkey.state == Mod5Mask); */ } break; case MapRequest: PanacheMapRequest (&report.xmaprequest); break; case UnmapNotify: { int state = PanacheGetWMState (report.xunmap.window); /*Mapped or Iconified*/ if (state == 1 || state == 3) { char *winId = NULL; char cmd[] = "sendToPipe [list remove $winId]"; winId = charMalloc (winIdLength); sprintf (winId, "%ld", report.xunmap.window); Tcl_SetVar (interp, "winId", winId, 0); free (winId); PanacheSetWMState (report.xunmap.window, WithdrawnState); if (Tcl_Eval (interp, cmd) != TCL_OK) { fprintf (stderr, "Tcl_Eval error in UnmapNotify within main() %s", Tcl_GetStringResult (interp)); } } } break; case PropertyNotify: { XTextProperty xtp; xtp.value = NULL; if (XGetWMName (dis, report.xproperty.window, &xtp) == 1) { char *winId; char cmd[] = "sendToPipe [list title [list $winTitle] $winId]"; winId = charMalloc (winIdLength); sprintf (winId, "%ld", report.xproperty.window); Tcl_SetVar (interp, "winTitle", (char *) xtp.value, 0); Tcl_SetVar (interp, "winId", winId, 0); free (winId); XFree (xtp.value); if (Tcl_Eval (interp, cmd) != TCL_OK) { fprintf (stderr, "Tcl_Eval error in PropertyNotify: within main() %s\n", Tcl_GetStringResult (interp)); } } } break; case ReparentNotify: { Window win = report.xreparent.window; Window parent = report.xreparent.parent; /* fprintf (stderr, "ReparentNotify\n"); fprintf (stderr, "win %ld parent %ld event %ld\n", win, parent, event); */ XSelectInput (dis, win, 0); if (parent != root) { char *winId; char cmd[] = "sendToPipe [list remove $winId]"; winId = charMalloc (winIdLength); sprintf (winId, "%ld", win); Tcl_SetVar (interp, "winId", winId, 0); free (winId); if (Tcl_Eval (interp, cmd) != TCL_OK) { fprintf (stderr, "Tcl_Eval error in ReparentNotify within main() %s\n", Tcl_GetStringResult (interp)); } } } break; case ResizeRequest: { Window twin; Window win = report.xresizerequest.window; if (XGetTransientForHint (dis, win, &twin) == 1) { XResizeWindow (dis, win, report.xresizerequest.width, report.xresizerequest.height ); } XFlush (dis); } break; default: break; } } } return 0; } |