gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

_handleWindowNeedsDisplay


From: David Ayers
Subject: _handleWindowNeedsDisplay
Date: Mon, 8 Jul 2002 21:31:09 +0200

Hello,

[David]
> I am definatly not aware of all the implications this would have,
> and I agree that the temporary disabling of the View's display
> seems like an appealing suggestion. I actually went as far as
> trying to replace the entire _handleWindowNeedsDisplay mechanism
> because I am (still) convinced, that it is insufficient to handle
> state dependant display. (I actually have something working at
> home and I'll be glad to post it on Saturday.)

OK it's not Saterday anymore. I've been busy trying make some type of
regression tests for DO in general. Since I was unsuccesfull in finding an
apropriate one, I started to write a little App and a server to test DO
basics. But, it isn't finished yet and it's posing other problems (see next
mail). In the mean time, I here are some results of my previous approches.

By now, I am pretty much convinced that:

1. display should only be executed in a "defined" state
2. the disable/enableFlushWindow mechanism can't insure the secure display
of _handleWindowNeedsDisplay: (see dragging)
3. the core of the problem is in the undeterminable execution of any
performSelector:target:argument:order:modes method
4. the (or rather a) solution lies in insuring a consistent display at any
time the app awaits user input.

The intent of this proposal was to offer a replacement for
_handleWindowNeedsDisplay: and all the corresponding
performSelector:target:argument:order:modes and
cancelPerformSelector:target:argument: calls! Yet during anlysis of Openstep
I found: An NSTextFieldPoser that ran [[NSRunLoop currentRunLoop]
runUntilDate:[NSDate date]] before returning, caused the same flashing
effect on OPENSTEP! So therefor I've put this patch on hold since it would
most likely alter the behavior of GNUstep a lot more than changing der mode
of the DO run loops. Yet since I said that I'll post it, here is what I had
done:

I've looked through the AppKit in search of THE place(s) to insure
consistent Display:
The most "central" place I have found to insure that the display is flushed
when the runloop is waiting for input is the GSDisplayServer. (Used by the
DPS functions. I was surprised not to find a lot more places, but I guess it
is the superior design efforts that lead to this "central" location :-) !)

Then I had to decide which method to use to flush. I'm not sure as to what
the exepected state of the app is when
"NS(Application/Window)(Will/Did)UpdateNotification" is posted but I found
that the cleanest way to insure all windows are up to date, is to use
NSApplications's updateWindows method. I would propose a private
updateWindows method for NSApplication, that just updates if it needs to,
i.e. _updateWindowsIfNeeded.

The GSDisplayServer then makes sure the display is up to date before going
into polling the runloop.

GSDisplayServer.m:

address@hidden NSApplication (secureWindowFlushing)
+- (void)_updateWindowsIfNeeded
+{
+  if (_windows_need_update)
+    {
+      [self updateWindows];
+    }
+}
address@hidden

@implementation GSDisplayServer (EventOps)
- (NSEvent*) getEventMatchingMask: (unsigned)mask
                       beforeDate: (NSDate*)limit
                           inMode: (NSString*)mode
                          dequeue: (BOOL)flag
{
  unsigned      pos = 0;        /* Position in queue scanned so far     */
  NSRunLoop     *loop = nil;

+ [NSApp _updateWindowsIfNeeded];
  do
    {
...
    }
  while ([loop runMode: mode beforeDate: limit] == YES);
...
}

yet if during runMode:beforeDate: some performSelector:target:... executed
that changes the UI (without flushing) and we want those also to be flushed,
then the better approach would be to put the updating code in the while
loop. This was my favored approach, and running the test apps I have right
now, it seems very reliable and perfomace is not noticably slower. I counted
the actual displays beeing done and they are pretty much the same. (Of
course there is minimal overhead through the repeated invocation if
_updateWindowsIfNeeded yet I find it negligable. Since NSApp isn't expected
to change during run time, caching the implementation of
_updateWindowsIfNeeded as a function pointer and invoking it as a function
would be feasable.)

@implementation GSDisplayServer (EventOps)
- (NSEvent*) getEventMatchingMask: (unsigned)mask
                       beforeDate: (NSDate*)limit
                           inMode: (NSString*)mode
                          dequeue: (BOOL)flag
{
...
      if (loop == nil)
        loop = [NSRunLoop currentRunLoop];

+     [NSApp _updateWindowsIfNeeded];
    }
  while ([loop runMode: mode beforeDate: limit] == YES);
...
}

If these seem to low a level, I would go back to NSApplication.m and insert
the update
at the following places:

NSApplication.m:
- (int) runModalSession: (NSModalSession)theSession
{
...
  /*
   * Set a limit date in the distant future so we wait until we get an
   * event.  We discard events that are not for this window.  When we
   * find one for this window, we push it back at the start of the queue.
   */
  limit = [NSDate distantFuture];
  do
    {
+     if (_windows_need_update)
+       {
+         [self updateWindows];
+       }

      event = DPSGetEvent(srv, NSAnyEventMask, limit, NSDefaultRunLoopMode);
      if (event != nil)
        {
          NSWindow      *eventWindow = [event window];

          if (eventWindow == theSession->window || [eventWindow worksWhenModal])
            {
              DPSPostEvent(srv, event, YES);
              found = YES;
            }
          else if ([event type] == NSAppKitDefined)
            {
              /* Handle resize and other window manager events now */
              [self sendEvent: event];
            }
        }
    }
  while (found == NO && theSession->runState == NSRunContinuesResponse);

  RELEASE (pool);
  /*
   *    Deal with the events in the queue.
   */

  while (found == YES && theSession->runState == NSRunContinuesResponse)
    {
      IF_NO_GC(pool = [arpClass new]);

+     if (_windows_need_update)
+       {
+         [self updateWindows];
+       }

      event = DPSGetEvent(srv, NSAnyEventMask, limit, NSDefaultRunLoopMode);
...
}

- (NSEvent*) nextEventMatchingMask: (unsigned int)mask
                         untilDate: (NSDate*)expiration
                            inMode: (NSString*)mode
                           dequeue: (BOOL)flag
{
  NSEvent       *event;

  if (!expiration)
    expiration = [NSDate distantFuture];

+ if (_windows_need_update)
+   {
+     [self updateWindows];
+   }

  if (flag)
    event = DPSGetEvent(GSCurrentServer(), mask, expiration, mode);
  else
    event = DPSPeekEvent(GSCurrentServer(), mask, expiration, mode);
...
}

But now I believe, that the chages in GSTcpPort
(NSDefaultRunLoopMode->NSConnectionReplayMode) should be the way to go,
since this would be the behavior mimicking Openstep the closest.

Thanx,
Dave




reply via email to

[Prev in Thread] Current Thread [Next in Thread]