92 metaDown <Boolean> true, if meta key (cmd-key) is currently pressed |
92 metaDown <Boolean> true, if meta key (cmd-key) is currently pressed |
93 altDown <Boolean> true, if alt key is currently pressed |
93 altDown <Boolean> true, if alt key is currently pressed |
94 |
94 |
95 motionEventCompression |
95 motionEventCompression |
96 |
96 |
97 lastId <Number> the id of the last events view (internal) |
97 lastId <Number> the id of the last events view (internal) |
98 lastView <View> the last events view (internal, for faster id->view mapping) |
98 lastView <View> the last events view (internal, for faster id->view mapping) |
99 |
99 |
100 keyboardMap <KeyBdMap> mapping for keys |
100 keyboardMap <KeyBdMap> mapping for keys |
101 isSlow <Boolean> set/cleared from startup - used to turn off |
101 isSlow <Boolean> set/cleared from startup - used to turn off |
102 things like popup-shadows etc. |
102 things like popup-shadows etc. |
103 " |
103 " |
176 |
177 |
177 self initializeFor:nil. |
178 self initializeFor:nil. |
178 |
179 |
179 " |
180 " |
180 first, all Forms must be recreated |
181 first, all Forms must be recreated |
181 (since they bay be needed for view recreation as |
182 (since they may be needed for view recreation as |
182 background or icons) |
183 background or icons) |
183 " |
184 " |
184 Form reinitializeAllOn:self. |
185 Form reinitializeAllOn:self. |
185 |
186 |
186 "/ prevMapping notNil ifTrue:[ |
187 "/ prevMapping notNil ifTrue:[ |
187 prevKnownViews notNil ifTrue:[ |
188 prevKnownViews notNil ifTrue:[ |
188 " |
189 " |
189 first round: flush all device specific stuff |
190 first round: flush all device specific stuff |
190 " |
191 " |
191 "/ prevMapping keysAndValuesDo:[:anId :aView | |
192 "/ prevMapping keysAndValuesDo:[:anId :aView | |
192 prevKnownViews do:[:aView | |
193 prevKnownViews do:[:aView | |
193 aView notNil ifTrue:[ |
194 aView notNil ifTrue:[ |
194 aView prepareForReinit |
195 aView prepareForReinit |
195 ] |
196 ] |
196 ]. |
197 ]. |
197 |
198 |
198 " |
199 " |
199 2nd round: all views should reinstall themself |
200 2nd round: all views should reinstall themself |
200 on the new display |
201 on the new display |
201 " |
202 " |
202 "/ prevMapping keysAndValuesDo:[:anId :aView | |
203 "/ prevMapping keysAndValuesDo:[:anId :aView | |
203 prevKnownViews do:[:aView | |
204 prevKnownViews do:[:aView | |
204 aView notNil ifTrue:[ |
205 aView notNil ifTrue:[ |
205 "have to re-create the view" |
206 "have to re-create the view" |
206 aView reinitialize |
207 aView reinitialize |
207 ] |
208 ] |
208 ]. |
209 ]. |
209 " |
210 " |
210 3rd round: all views get a chance to handle |
211 3rd round: all views get a chance to handle |
211 changed environment (colors, font sizes etc) |
212 changed environment (colors, font sizes etc) |
212 " |
213 " |
213 "/ prevMapping keysAndValuesDo:[:anId :aView | |
214 "/ prevMapping keysAndValuesDo:[:anId :aView | |
214 prevKnownViews do:[:aView | |
215 prevKnownViews do:[:aView | |
215 aView notNil ifTrue:[ |
216 aView notNil ifTrue:[ |
216 aView reAdjustGeometry |
217 aView reAdjustGeometry |
217 ] |
218 ] |
218 ] |
219 ] |
851 |
854 |
852 sendKeyPress:untranslatedKey x:x y:y to:someone |
855 sendKeyPress:untranslatedKey x:x y:y to:someone |
853 "forward a key-press event to some handler; |
856 "forward a key-press event to some handler; |
854 the key is translated via the translation table here." |
857 the key is translated via the translation table here." |
855 |
858 |
856 |key xlatedKey| |
859 |xlatedKey| |
857 |
860 |
858 key := untranslatedKey. |
861 xlatedKey := self translateKey:untranslatedKey. |
859 controlDown ifTrue:[ |
|
860 (key size == 1) ifTrue:[ "a single character" |
|
861 key := ('Ctrl' , untranslatedKey asString) asSymbol |
|
862 ] |
|
863 ]. |
|
864 metaDown ifTrue:[ |
|
865 (untranslatedKey isMemberOf:Character) ifTrue:[ |
|
866 key := ('Cmd' , untranslatedKey asString) asSymbol |
|
867 ] |
|
868 ]. |
|
869 altDown ifTrue:[ |
|
870 (untranslatedKey isMemberOf:Character) ifTrue:[ |
|
871 key := ('Alt' , untranslatedKey asString) asSymbol |
|
872 ] |
|
873 ]. |
|
874 |
|
875 |
|
876 xlatedKey := keyboardMap valueFor:key. |
|
877 xlatedKey notNil ifTrue:[ |
862 xlatedKey notNil ifTrue:[ |
878 someone delegate notNil ifTrue:[ |
863 someone delegate notNil ifTrue:[ |
879 someone delegate keyPress:xlatedKey x:x y:y view:someone |
864 someone delegate keyPress:xlatedKey x:x y:y view:someone |
880 ] ifFalse:[ |
865 ] ifFalse:[ |
881 someone keyPress:xlatedKey x:x y:y |
866 someone keyPress:xlatedKey x:x y:y |
882 ] |
867 ] |
883 ] |
868 ] |
|
869 ! |
|
870 |
|
871 translateKey:untranslatedKey |
|
872 "Return the key translated via the translation table. |
|
873 |
|
874 First, the modifier is prepended, making character X into |
|
875 AltX, CtrlX or CmdX (on most systems, no separate Cmd (or Meta) |
|
876 key exists; on those we always get AltX). |
|
877 Then the result is used as a key into the translation keyboardMap |
|
878 to get the final return value." |
|
879 |
|
880 |xlatedKey| |
|
881 |
|
882 xlatedKey := untranslatedKey. |
|
883 controlDown ifTrue:[ |
|
884 (xlatedKey size == 1) ifTrue:[ "a single character" |
|
885 xlatedKey := ('Ctrl' , untranslatedKey asString) asSymbol |
|
886 ]. |
|
887 ]. |
|
888 metaDown ifTrue:[ |
|
889 (untranslatedKey isMemberOf:Character) ifTrue:[ |
|
890 xlatedKey := ('Cmd' , untranslatedKey asString) asSymbol |
|
891 ] |
|
892 ]. |
|
893 altDown ifTrue:[ |
|
894 (untranslatedKey isMemberOf:Character) ifTrue:[ |
|
895 xlatedKey := ('Alt' , untranslatedKey asString) asSymbol |
|
896 ] |
|
897 ]. |
|
898 |
|
899 xlatedKey := keyboardMap valueFor:xlatedKey. |
|
900 ^ xlatedKey |
884 ! ! |
901 ! ! |
885 |
902 |
886 !DeviceWorkstation methodsFor:'private'! |
903 !DeviceWorkstation methodsFor:'private'! |
887 |
904 |
888 addKnownView:aView withId:aNumber |
905 addKnownView:aView withId:aNumber |
889 "add the View aView with Id:aNumber to the list of known views/id's" |
906 "add the View aView with Id:aNumber to the list of known views/id's. |
|
907 This map is needed later (on event arrival) to get the view from |
|
908 the views id (which is passed along with the devices event) quickly." |
890 |
909 |
891 "/ idToViewMapping isNil ifTrue:[ |
910 "/ idToViewMapping isNil ifTrue:[ |
892 "/ idToViewMapping := IdentityDictionary new. |
911 "/ idToViewMapping := IdentityDictionary new. |
893 "/ ]. |
912 "/ ]. |
894 "/ idToViewMapping at:aNumber put:aView. |
913 "/ idToViewMapping at:aNumber put:aView. |
895 |
914 |
896 knownViews isNil ifTrue:[ |
915 knownViews isNil ifTrue:[ |
897 knownViews := OrderedCollection new "(VariableArray new:100) grow:0". |
916 knownViews := OrderedCollection new:50. |
898 knownIds := OrderedCollection new "(VariableArray new:100) grow:0" |
917 knownIds := OrderedCollection new:50. |
899 ]. |
918 ]. |
900 knownViews add:aView. |
919 knownViews add:aView. |
901 knownIds add:aNumber. |
920 knownIds add:aNumber. |
902 |
921 |
903 lastView := aView. |
922 lastView := aView. |
904 lastId := aNumber |
923 lastId := aNumber |
905 ! |
924 ! |
906 |
925 |
907 removeKnownView:aView |
926 removeKnownView:aView |
908 "remove aView from the list of known views/id's" |
927 "remove aView from the list of known views/id's." |
909 |
928 |
910 "/ idToViewMapping removeValue:aView ifAbsent:[]. |
929 "/ idToViewMapping removeValue:aView ifAbsent:[]. |
911 "/ lastId := nil. |
930 "/ lastId := nil. |
912 "/ lastView := nil |
931 "/ lastView := nil |
913 |
932 |
969 |
988 |
970 restoreCursors |
989 restoreCursors |
971 "restore the cursors of all views to their current cursor" |
990 "restore the cursors of all views to their current cursor" |
972 |
991 |
973 "/ idToViewMapping notNil ifTrue:[ |
992 "/ idToViewMapping notNil ifTrue:[ |
974 "/ idToViewMapping keysAndValuesDo:[:viewId :view | |
993 "/ idToViewMapping keysAndValuesDo:[:viewId :view | |
975 "/ |curs cid| |
994 "/ |curs cid| |
976 "/ curs := view cursor. |
995 "/ curs := view cursor. |
977 "/ curs notNil ifTrue:[ |
996 "/ curs notNil ifTrue:[ |
978 "/ cid := curs id. |
997 "/ cid := curs id. |
979 "/ cid notNil ifTrue:[ |
998 "/ cid notNil ifTrue:[ |
980 "/ self setCursor:cid in:viewId |
999 "/ self setCursor:cid in:viewId |
981 "/ ] |
1000 "/ ] |
982 "/ ] |
1001 "/ ] |
983 "/ ]. |
1002 "/ ]. |
984 "/ self synchronizeOutput |
1003 "/ self synchronizeOutput |
985 "/ ] |
1004 "/ ] |
986 |
1005 |
987 knownViews notNil ifTrue:[ |
1006 knownViews notNil ifTrue:[ |
988 knownViews do:[:aView | |
1007 knownViews do:[:aView | |
1004 !DeviceWorkstation methodsFor:'events'! |
1023 !DeviceWorkstation methodsFor:'events'! |
1005 |
1024 |
1006 startDispatch |
1025 startDispatch |
1007 "create the display dispatch process" |
1026 "create the display dispatch process" |
1008 |
1027 |
1009 |sema fd p| |
1028 |inputSema fd p| |
1010 |
1029 |
1011 dispatching ifTrue:[^ self]. |
1030 dispatching ifTrue:[^ self]. |
1012 dispatching := true. |
1031 dispatching := true. |
1013 |
1032 |
1014 fd := self displayFileDescriptor. |
1033 fd := self displayFileDescriptor. |
1015 |
1034 |
1016 ProcessorScheduler isPureEventDriven ifTrue:[ |
1035 ProcessorScheduler isPureEventDriven ifTrue:[ |
1017 "handle all events by having preocessor call a block when something |
1036 " |
1018 arrives on my filedescriptor" |
1037 no threads built in; |
1019 |
1038 handle all events by having processor call a block when something |
|
1039 arrives on my filedescriptor |
|
1040 " |
1020 Processor enableIOAction:[ |
1041 Processor enableIOAction:[ |
1021 dispatching ifTrue:[ |
1042 dispatching ifTrue:[ |
1022 [self eventPending] whileTrue:[ |
1043 [self eventPending] whileTrue:[ |
1023 self dispatchPendingEvents. |
1044 self dispatchPendingEvents. |
1024 self checkForEndOfDispatch. |
1045 self checkForEndOfDispatch. |
1029 ] |
1050 ] |
1030 ] |
1051 ] |
1031 on:fd |
1052 on:fd |
1032 |
1053 |
1033 ] ifFalse:[ |
1054 ] ifFalse:[ |
1034 "handle stuff as a process - sitting on a semaphore. |
1055 " |
|
1056 handle stuff as a process - sitting on a semaphore. |
1035 Tell Processor to trigger this semaphore when something arrives |
1057 Tell Processor to trigger this semaphore when something arrives |
1036 on my filedescriptor" |
1058 on my filedescriptor. Since a select alone is not enough to |
1037 |
1059 know if events are pending (Xlib reads out event-queue while |
1038 sema := Semaphore new. |
1060 doing output), we also have to install a poll-check block. |
|
1061 " |
|
1062 inputSema := Semaphore new. |
1039 p := [ |
1063 p := [ |
1040 [dispatching] whileTrue:[ |
1064 [dispatching] whileTrue:[ |
1041 self eventPending ifFalse:[ |
1065 self eventPending ifFalse:[ |
1042 Processor enableSemaphore:sema onInput:fd check:[self eventPending]. |
1066 inputSema wait. |
1043 sema wait. |
|
1044 Processor disableSemaphore:sema |
|
1045 ]. |
1067 ]. |
1046 |
1068 |
|
1069 " |
|
1070 in case of an error in the dispatch (i.e. WSensor |
|
1071 is broken) AND user presses abort in the debugger, |
|
1072 we want to continue here. |
|
1073 " |
|
1074 Object abortSignal catch:[ |
|
1075 self dispatchPendingEvents. |
|
1076 ]. |
1047 self dispatchPendingEvents. |
1077 self dispatchPendingEvents. |
1048 self checkForEndOfDispatch. |
1078 self checkForEndOfDispatch. |
1049 |
1079 |
1050 dispatching ifFalse:[ |
1080 dispatching ifFalse:[ |
1051 sema := nil |
1081 Processor disableSemaphore:inputSema. |
|
1082 inputSema := nil |
1052 ] |
1083 ] |
1053 ] |
1084 ] |
1054 ] forkAt:(Processor userSchedulingPriority). |
1085 ] forkAt:(Processor userInterruptPriority). |
1055 p name:'event dispatcher' |
1086 " |
|
1087 give the process a nice name |
|
1088 " |
|
1089 p name:'event dispatcher'. |
|
1090 Processor signal:inputSema onInput:fd orCheck:[self eventPending]. |
1056 ] |
1091 ] |
1057 ! |
1092 ! |
1058 |
1093 |
1059 checkForEndOfDispatch |
1094 checkForEndOfDispatch |
1060 "return true, if there are still any views of interrest - |
1095 "return true, if there are still any views of interrest - |
1061 if not, stop dispatch" |
1096 if not, stop dispatch" |
1062 |
1097 |
1063 self == Display ifTrue:[ |
1098 self == Display ifTrue:[ |
1064 "/ idToViewMapping isEmpty ifTrue:[ |
1099 "/ idToViewMapping isEmpty ifTrue:[ |
1065 knownViews isEmpty ifTrue:[ |
1100 knownViews isEmpty ifTrue:[ |
1066 dispatching := false |
1101 dispatching := false |
1067 ] |
1102 ] |
1068 ] |
1103 ] |
1069 ! |
1104 ! |
1077 ! |
1112 ! |
1078 |
1113 |
1079 dispatchModalWhile:aBlock |
1114 dispatchModalWhile:aBlock |
1080 "get and process next event for any view as long as the |
1115 "get and process next event for any view as long as the |
1081 argument-block evaluates to true. |
1116 argument-block evaluates to true. |
1082 This is a modal loop, not switching to other processes." |
1117 This is a modal loop, not switching to other processes, |
1083 |
1118 effectively polling the device in a (nice) busy loop. |
|
1119 This should only be used for emergency cases. |
|
1120 (such as a graphical debugger, debugging the event-dispatcher itself)" |
|
1121 |
|
1122 |myFd| |
|
1123 |
|
1124 " |
|
1125 if this display has a fileDescriptor to wait on, |
|
1126 it is used; otherwise we poll (with a delay to not lock up |
|
1127 the workstation) |
|
1128 " |
|
1129 myFd := self displayFileDescriptor. |
1084 [aBlock value] whileTrue:[ |
1130 [aBlock value] whileTrue:[ |
1085 self eventPending ifFalse:[ |
1131 self eventPending ifFalse:[ |
|
1132 myFd isNil ifTrue:[ |
|
1133 OperatingSystem millisecondDelay:50 |
|
1134 ] ifFalse:[ |
|
1135 OperatingSystem selectOn:myFd withTimeOut:50. |
|
1136 ]. |
1086 Processor evaluateTimeouts. |
1137 Processor evaluateTimeouts. |
1087 OperatingSystem millisecondDelay:50. |
|
1088 ]. |
1138 ]. |
1089 self dispatchEvent |
1139 self eventPending ifTrue:[ |
1090 ]. |
1140 self dispatchEvent |
|
1141 ]. |
|
1142 ] |
1091 ! |
1143 ! |
1092 |
1144 |
1093 dispatchEvent |
1145 dispatchEvent |
1094 "get and process next event for any view" |
1146 "get and process next event for any view" |
1095 |
1147 |
1237 |allFonts families family| |
1293 |allFonts families family| |
1238 |
1294 |
1239 allFonts := self listOfAvailableFonts. |
1295 allFonts := self listOfAvailableFonts. |
1240 allFonts isNil ifTrue:[^ nil]. |
1296 allFonts isNil ifTrue:[^ nil]. |
1241 families := Set new. |
1297 families := Set new. |
1242 allFonts do:[:arr | |
1298 allFonts do:[:fntDescr | |
1243 family := arr at:1. |
1299 "/ old: |
|
1300 "/ family := fntDescr at:1. |
|
1301 "/ new: |
|
1302 family := fntDescr family. |
1244 family notNil ifTrue:[ |
1303 family notNil ifTrue:[ |
1245 families add:family |
1304 families add:family |
1246 ] |
1305 ] |
1247 ]. |
1306 ]. |
1248 ^ families |
1307 ^ families |
1249 |
1308 |
1250 "Display fontFamilies" |
1309 " |
|
1310 Display fontFamilies |
|
1311 " |
1251 ! |
1312 ! |
1252 |
1313 |
1253 facesInFamily:aFamilyName |
1314 facesInFamily:aFamilyName |
1254 "return a set of all available font faces in aFamily on this display" |
1315 "return a set of all available font faces in aFamily on this display" |
1255 |
1316 |
1256 |allFonts faces family face| |
1317 |allFonts faces family face| |
1257 |
1318 |
1258 allFonts := self listOfAvailableFonts. |
1319 allFonts := self listOfAvailableFonts. |
1259 allFonts isNil ifTrue:[^ nil]. |
1320 allFonts isNil ifTrue:[^ nil]. |
|
1321 |
1260 faces := Set new. |
1322 faces := Set new. |
1261 allFonts do:[:arr | |
1323 allFonts do:[:fntDescr | |
1262 family := arr at:1. |
1324 "/ old: |
1263 (family = aFamilyName) ifTrue:[ |
1325 "/ family := fntDescr at:1. |
1264 face := arr at:2. |
1326 "/ (family = aFamilyName) ifTrue:[ |
1265 faces add:face |
1327 "/ face := fntDescr at:2. |
|
1328 "/ faces add:face |
|
1329 "/ ] |
|
1330 "/ new: |
|
1331 fntDescr family = aFamilyName ifTrue:[ |
|
1332 faces add:(fntDescr face) |
1266 ] |
1333 ] |
1267 ]. |
1334 ]. |
1268 ^ faces |
1335 ^ faces |
1269 |
1336 |
1270 "Display facesInFamily:'times'" |
1337 " |
1271 "Display facesInFamily:'fixed'" |
1338 Display facesInFamily:'times' |
|
1339 Display facesInFamily:'fixed' |
|
1340 " |
1272 ! |
1341 ! |
1273 |
1342 |
1274 stylesInFamily:aFamilyName face:aFaceName |
1343 stylesInFamily:aFamilyName face:aFaceName |
1275 "return a set of all available font styles in aFamily/aFace on this display" |
1344 "return a set of all available font styles in aFamily/aFace on this display" |
1276 |
1345 |
1277 |allFonts styles family face style| |
1346 |allFonts styles family face style| |
1278 |
1347 |
1279 allFonts := self listOfAvailableFonts. |
1348 allFonts := self listOfAvailableFonts. |
1280 allFonts isNil ifTrue:[^ nil]. |
1349 allFonts isNil ifTrue:[^ nil]. |
|
1350 |
1281 styles := Set new. |
1351 styles := Set new. |
1282 allFonts do:[:arr | |
1352 allFonts do:[:fntDescr | |
1283 family := arr at:1. |
1353 "/ old: |
1284 (family = aFamilyName) ifTrue:[ |
1354 "/ family := fntDescr at:1. |
1285 face := arr at:2. |
1355 "/ (family = aFamilyName) ifTrue:[ |
1286 (face = aFaceName) ifTrue:[ |
1356 "/ face := fntDescr at:2. |
1287 style := arr at:3. |
1357 "/ (face = aFaceName) ifTrue:[ |
1288 styles add:style |
1358 "/ style := fntDescr at:3. |
|
1359 "/ styles add:style |
|
1360 "/ ] |
|
1361 "/ ] |
|
1362 (fntDescr family = aFamilyName) ifTrue:[ |
|
1363 (fntDescr face = aFaceName) ifTrue:[ |
|
1364 styles add:fntDescr style |
1289 ] |
1365 ] |
1290 ] |
1366 ] |
1291 ]. |
1367 ]. |
1292 ^ styles |
1368 ^ styles |
1293 |
1369 |
1294 "Display stylesInFamily:'times' face:'medium'" |
1370 " |
1295 "Display stylesInFamily:'times' face:'bold'" |
1371 Display stylesInFamily:'times' face:'medium' |
|
1372 Display stylesInFamily:'times' face:'bold' |
|
1373 " |
1296 ! |
1374 ! |
1297 |
1375 |
1298 sizesInFamily:aFamilyName face:aFaceName style:aStyleName |
1376 sizesInFamily:aFamilyName face:aFaceName style:aStyleName |
1299 "return a set of all available font sizes in aFamily/aFace/aStyle |
1377 "return a set of all available font sizes in aFamily/aFace/aStyle |
1300 on this display" |
1378 on this display" |
1301 |
1379 |
1302 |allFonts sizes family face style size| |
1380 |allFonts sizes family face style size| |
1303 |
1381 |
1304 allFonts := self listOfAvailableFonts. |
1382 allFonts := self listOfAvailableFonts. |
1305 allFonts isNil ifTrue:[^ nil]. |
1383 allFonts isNil ifTrue:[^ nil]. |
|
1384 |
1306 sizes := Set new. |
1385 sizes := Set new. |
1307 allFonts do:[:arr | |
1386 allFonts do:[:fntDescr | |
1308 family := arr at:1. |
1387 "/ family := fntDescr at:1. |
1309 (family = aFamilyName) ifTrue:[ |
1388 "/ (family = aFamilyName) ifTrue:[ |
1310 face := arr at:2. |
1389 "/ face := fntDescr at:2. |
1311 (face = aFaceName) ifTrue:[ |
1390 "/ (face = aFaceName) ifTrue:[ |
1312 style := arr at:3. |
1391 "/ style := fntDescr at:3. |
1313 (style = aStyleName) ifTrue:[ |
1392 "/ (style = aStyleName) ifTrue:[ |
1314 size := arr at:4. |
1393 "/ size := fntDescr at:4. |
1315 sizes add:size |
1394 "/ sizes add:size |
|
1395 "/ ] |
|
1396 "/ ] |
|
1397 "/ ] |
|
1398 (fntDescr family = aFamilyName) ifTrue:[ |
|
1399 (fntDescr face = aFaceName) ifTrue:[ |
|
1400 (fntDescr style = aStyleName) ifTrue:[ |
|
1401 sizes add:fntDescr size |
1316 ] |
1402 ] |
1317 ] |
1403 ] |
1318 ] |
1404 ] |
1319 ]. |
1405 ]. |
1320 ^ sizes |
1406 ^ sizes |
1321 |
1407 |
1322 "Display sizesInFamily:'times' face:'medium' style:'italic'" |
1408 " |
|
1409 Display sizesInFamily:'times' face:'medium' style:'italic' |
|
1410 " |
1323 ! |
1411 ! |
1324 |
1412 |
1325 getFontWithFamily:familyString |
1413 getFontWithFamily:familyString |
1326 face:faceString |
1414 face:faceString |
1327 style:styleString |
1415 style:styleString |