263 |
264 |
264 processEvent |
265 processEvent |
265 "process a single event from either the damage- or user input queues. |
266 "process a single event from either the damage- or user input queues. |
266 Debugger abort brings us back here." |
267 Debugger abort brings us back here." |
267 |
268 |
268 |event| |
269 |event ignore| |
269 |
270 |
270 self processExposeEvents. |
271 self processExposeEvents. |
271 [mySensor hasEvents] whileTrue:[ |
272 [mySensor hasEvents] whileTrue:[ |
272 event := mySensor nextEvent. |
273 event := mySensor nextEvent. |
273 (views isNil and:[topViews isNil]) ifFalse:[ |
274 event notNil ifTrue:[ |
274 event sendEvent. |
275 (views isNil and:[topViews isNil]) ifFalse:[ |
|
276 |
|
277 ignore := false. |
|
278 event isKeyPressEvent ifTrue:[ |
|
279 event key == #FocusNext ifTrue:[ |
|
280 self focusNext. |
|
281 ignore := true |
|
282 ]. |
|
283 event key == #FocusPrevious ifTrue:[ |
|
284 self focusPrevious. |
|
285 ignore := true |
|
286 ]. |
|
287 ]. |
|
288 " |
|
289 button events turn off explicit focus, and revert |
|
290 to implicit focus control |
|
291 " |
|
292 (focusView notNil |
|
293 and:[event isButtonEvent]) ifTrue:[ |
|
294 self focusView:nil |
|
295 ]. |
|
296 |
|
297 ignore ifFalse:[ |
|
298 AbortSignal catch:[ |
|
299 event sendEventWithFocusOn:focusView. |
|
300 ] |
|
301 ] |
|
302 ] |
275 ]. |
303 ]. |
276 ] |
304 ] |
277 ! |
305 ! |
278 |
306 |
279 processExposeEvents |
307 processExposeEvents |
280 "process all expose events from the damage queue" |
308 "process all expose events from the damage queue" |
281 |
309 |
282 |event view rect oldActive| |
310 |event view rect oldActive x y w h| |
283 |
311 |
284 oldActive := ActiveGroup. |
312 oldActive := ActiveGroup. |
285 ActiveGroup := self. |
313 [ |
286 [mySensor notNil and:[mySensor hasDamage]] whileTrue:[ |
314 [mySensor notNil and:[mySensor hasDamage]] whileTrue:[ |
287 event := mySensor nextDamage. |
315 ActiveGroup := self. |
288 event notNil ifTrue:[ |
316 event := mySensor nextDamage. |
289 (views isNil and:[topViews isNil]) ifFalse:[ |
317 event notNil ifTrue:[ |
290 event isDamage ifTrue:[ |
318 (views isNil and:[topViews isNil]) ifFalse:[ |
291 view := event view. |
319 event isDamage ifTrue:[ |
292 rect := event rectangle. |
320 view := event view. |
293 view shown ifTrue:[ |
321 rect := event rectangle. |
294 view transformation notNil ifTrue:[ |
322 view shown ifTrue:[ |
295 view deviceExposeX:(rect left) y:(rect top) width:(rect width) height:(rect height) |
323 rect := event rectangle. |
296 ] ifFalse:[ |
324 x := rect left. |
297 view exposeX:(rect left) y:(rect top) width:(rect width) height:(rect height) |
325 y := rect top. |
|
326 w := rect width. |
|
327 h := rect height. |
|
328 view transformation notNil ifTrue:[ |
|
329 view deviceExposeX:x y:y width:w height:h |
|
330 ] ifFalse:[ |
|
331 view exposeX:x y:y width:w height:h |
|
332 ] |
298 ] |
333 ] |
|
334 ] ifFalse:[ |
|
335 " |
|
336 mhmh - could we possibly arrive here ? |
|
337 " |
|
338 event sendEvent. |
299 ] |
339 ] |
300 ] ifFalse:[ |
|
301 event sendEvent. |
|
302 ] |
340 ] |
303 ] |
341 ] |
304 ] |
342 ] |
305 ]. |
343 ] valueNowOrOnUnwindDo:[ |
306 ActiveGroup := oldActive |
344 ActiveGroup := oldActive. |
|
345 oldActive := nil |
|
346 ] |
307 ! |
347 ! |
308 |
348 |
309 eventLoop |
349 eventLoop |
310 "loop executed by windowGroup process; |
350 "loop executed by windowGroup process; |
311 wait-for and process events forever" |
351 wait-for and process events forever" |
312 |
352 |
313 self eventLoopWhile:[true] |
353 self eventLoopWhile:[true] |
314 ! |
354 ! |
315 |
355 |
316 eventLoopWhile:aBlock |
356 eventLoopWhile:aBlock |
317 "wait-for and process events while aBlock evaluates to true." |
357 "wait-for and process events. |
318 |
358 Stay in this loop while there are still any views to dispatch for, |
319 |abortSignal| |
359 and aBlock evaluates to true." |
320 |
360 |
321 abortSignal := Object abortSignal. |
361 |oldActive| |
322 "/ ScheduledWindowGroups add:self. |
362 |
323 |
363 oldActive := ActiveGroup. |
324 (SignalSet with:LeaveSignal with:abortSignal) |
364 "/ ScheduledWindowGroups add:self. |
325 handle:[:ex | |
365 |
326 ex return |
366 [ |
327 ] do:[ |
367 (SignalSet with:LeaveSignal with:AbortSignal) |
328 |p g oldActive mainGroup| |
368 handle:[:ex | |
329 |
369 "/ ActiveGroup := oldActive. |
330 isModal ifTrue:[ |
370 "/ oldActive := nil. |
331 mainGroup := self mainGroup. |
371 ex return |
|
372 ] do:[ |
|
373 |p g mainGroup| |
|
374 |
|
375 isModal ifTrue:[ |
|
376 mainGroup := self mainGroup. |
|
377 ]. |
|
378 |
|
379 aBlock whileTrue:[ |
|
380 (views isNil and:[topViews isNil]) ifTrue:[ |
|
381 "/ ScheduledWindowGroups remove:self ifAbsent:[]. |
|
382 myProcess notNil ifTrue:[ |
|
383 p := myProcess. |
|
384 myProcess := nil. |
|
385 p terminate. |
|
386 "not reached - there is no life after death" |
|
387 ]. |
|
388 " |
|
389 this is the end of a modal loop |
|
390 (not having a private process ...) |
|
391 " |
|
392 ^ self |
|
393 ]. |
|
394 |
|
395 AbortSignal handle:[:ex | |
|
396 "/ ActiveGroup := oldActive. |
|
397 "/ oldActive := nil. |
|
398 ex return |
|
399 ] do:[ |
|
400 " |
|
401 if modal, break out of the wait after some time |
|
402 to allow servicing update-events of the blocked |
|
403 windowgroup. |
|
404 " |
|
405 Processor activeProcess setStateTo:#eventWait if:#active. |
|
406 isModal ifTrue:[ |
|
407 mySensor eventSemaphore waitWithTimeout:0.2. |
|
408 ] ifFalse:[ |
|
409 mySensor eventSemaphore wait. |
|
410 ]. |
|
411 ActiveGroup := self. |
|
412 self processEvent |
|
413 ]. |
|
414 "/ ActiveGroup := oldActive. |
|
415 |
|
416 " |
|
417 if modal, also check for redraw events in my maingroup |
|
418 (we arrive here after every event for myself or after the |
|
419 above timeout) |
|
420 " |
|
421 mainGroup notNil ifTrue:[ |
|
422 mainGroup processExposeEvents. |
|
423 ] |
|
424 ] |
332 ]. |
425 ]. |
333 |
426 ] valueNowOrOnUnwindDo:[ |
334 aBlock whileTrue:[ |
427 "/ ScheduledWindowGroups remove:self ifAbsent:[]. |
335 (views isNil and:[topViews isNil]) ifTrue:[ |
428 ActiveGroup := oldActive. |
336 "/ ScheduledWindowGroups remove:self ifAbsent:[]. |
429 oldActive := nil. |
337 myProcess notNil ifTrue:[ |
430 ]. |
338 p := myProcess. |
|
339 myProcess := nil. |
|
340 p terminate. |
|
341 "not reached - there is no life after death" |
|
342 ]. |
|
343 " |
|
344 this is the end of a modal loop |
|
345 (not having a private process ...) |
|
346 " |
|
347 ^ self |
|
348 ]. |
|
349 abortSignal handle:[:ex | |
|
350 ex return |
|
351 ] do:[ |
|
352 " |
|
353 if modal, break out of the wait after some time |
|
354 to allow servicing update-events of the blocked |
|
355 windowgroup. |
|
356 " |
|
357 isModal ifTrue:[ |
|
358 mySensor eventSemaphore waitWithTimeout:0.2. |
|
359 ] ifFalse:[ |
|
360 Processor activeProcess setStateTo:#eventWait if:#active. |
|
361 mySensor eventSemaphore wait. |
|
362 ]. |
|
363 oldActive := ActiveGroup. |
|
364 ActiveGroup := self. |
|
365 self processEvent |
|
366 ]. |
|
367 ActiveGroup := oldActive. |
|
368 oldActive := nil. |
|
369 |
|
370 " |
|
371 if modal, also check for redraw events in my maingroup |
|
372 (we arrive here after every event for myself or after the |
|
373 above timeout) |
|
374 " |
|
375 mainGroup notNil ifTrue:[ |
|
376 mainGroup processExposeEvents. |
|
377 ] |
|
378 ] |
|
379 ]. |
|
380 "/ ScheduledWindowGroups remove:self ifAbsent:[]. |
|
381 ! |
431 ! |
382 |
432 |
383 waitForExposeFor:aView |
433 waitForExposeFor:aView |
384 "wait for a noExpose on aView, then process all exposes. |
434 "wait for a noExpose on aView, then process all exposes. |
385 To be used after a scroll" |
435 To be used after a scroll" |
386 |
436 |
387 mySensor waitForExposeFor:aView. |
437 mySensor waitForExposeFor:aView. |
388 self processExposeEvents |
438 AbortSignal catch:[ |
|
439 self processExposeEvents |
|
440 ] |
389 ! |
441 ! |
390 |
442 |
391 leaveEventLoop |
443 leaveEventLoop |
392 ^ LeaveSignal raise |
444 ^ LeaveSignal raise |
393 ! ! |
445 ! ! |
542 mySensor := WindowSensor new. |
593 mySensor := WindowSensor new. |
543 mySensor eventSemaphore:Semaphore new. |
594 mySensor eventSemaphore:Semaphore new. |
544 isModal := false. |
595 isModal := false. |
545 ! ! |
596 ! ! |
546 |
597 |
|
598 !WindowGroup methodsFor:'focus control'! |
|
599 |
|
600 focusSequence:aSequenceableCollection |
|
601 "define the focus sequence for focusNext/focusPrevious. |
|
602 Focus is stepped in the order in which subviews occur in |
|
603 the sequence" |
|
604 |
|
605 focusSequence := aSequenceableCollection |
|
606 ! |
|
607 |
|
608 focusView |
|
609 "return the view which has the focus" |
|
610 |
|
611 ^ focusView |
|
612 ! |
|
613 |
|
614 focusView:aViewOrNil |
|
615 "give focus to aViewOrNil" |
|
616 |
|
617 focusView notNil ifTrue:[ |
|
618 focusView focusOut. |
|
619 ]. |
|
620 focusView := aViewOrNil. |
|
621 focusView notNil ifTrue:[ |
|
622 focusView focusIn |
|
623 ]. |
|
624 |
|
625 " |
|
626 |top v1 v2| |
|
627 |
|
628 top := StandardSystemView new. |
|
629 v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top. |
|
630 v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top. |
|
631 top open. |
|
632 top windowGroup focusView:v1. |
|
633 " |
|
634 ! |
|
635 |
|
636 focusNext |
|
637 "give focus to next view in focusSequence" |
|
638 |
|
639 |index| |
|
640 |
|
641 focusSequence isNil ifTrue:[^ self]. |
|
642 focusView notNil ifTrue:[ |
|
643 index := (focusSequence indexOf:focusView) + 1. |
|
644 index > focusSequence size ifTrue:[index := 1]. |
|
645 ] ifFalse:[ |
|
646 index := 1. |
|
647 ]. |
|
648 self focusView:(focusSequence at:index) |
|
649 |
|
650 " |
|
651 |top v1 v2| |
|
652 |
|
653 top := StandardSystemView new. |
|
654 v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top. |
|
655 v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top. |
|
656 top open. |
|
657 top windowGroup focusSequence:(Array with:v1 with:v2). |
|
658 top windowGroup focusOn:v1. |
|
659 (Delay forSeconds:10) wait. |
|
660 top windowGroup focusNext. |
|
661 " |
|
662 ! |
|
663 |
|
664 focusPrevious |
|
665 "give focus to previous view in focusSequence" |
|
666 |
|
667 |index| |
|
668 |
|
669 focusSequence isNil ifTrue:[^ self]. |
|
670 focusView notNil ifTrue:[ |
|
671 index := (focusSequence indexOf:focusView) - 1. |
|
672 index < 1 ifTrue:[index := focusSequence size]. |
|
673 ] ifFalse:[ |
|
674 index := focusSequence size. |
|
675 ]. |
|
676 self focusView:(focusSequence at:index) |
|
677 ! ! |
|
678 |
547 !WindowGroup methodsFor:'printing'! |
679 !WindowGroup methodsFor:'printing'! |
548 |
680 |
549 printString |
681 printOn:aStream |
550 "return a printed representation; |
682 "return a printed representation; |
551 just for more user friendlyness, add name of process." |
683 just for more user friendlyness, add name of process." |
552 |
684 |
553 myProcess isNil ifTrue:[^ super printString]. |
685 myProcess isNil ifTrue:[ |
554 ^ 'WindowGroup(' , myProcess nameOrId , ')' |
686 (previousGroup notNil and:[previousGroup process notNil]) ifTrue:[ |
555 ! ! |
687 aStream nextPutAll:('WindowGroup(modal in ' , previousGroup process nameOrId , ')'). |
|
688 ^ self. |
|
689 ]. |
|
690 ^ super printOn:aStream |
|
691 ]. |
|
692 aStream nextPutAll:('WindowGroup(' , myProcess nameOrId , ')') |
|
693 ! ! |