[interfacekit] Re: sync

Normally there shouldn't be any problem occuring, and everything should stay
nicely synchronized.

When you call ResizeTo, the following happens:

void BView::ResizeTo(float width, float height)
{
        if (owner)
                movesize(B_VIEW_RESIZE_TO, width, height);
        else
        {
                fCachedBounds.right = fCachedBounds.left + width;
                fCachedBounds.bottom = fCachedBounds.top + height;
        }
}

void BView::movesize(uint32 code, int32 h, int32 v)
{
        if (!owner)
                return;

        owner->check_lock();

        owner->a_session->swrite_l(code);
        owner->a_session->swrite_l(server_token);
        owner->a_session->swrite_l(h);
        owner->a_session->swrite_l(v);
}

The message is build and stored in the session. Note that since we are
attached to a window, we don't use/modify local data (fCachedBounds).

When we call Frame(), the following happens (I cut out the code used when
printing or using hidden views to simplify):

BRect BView::Frame() const
{
        BRect rect;

        if (server_token == -1)
                rect = fCachedBounds;
        else
        {
                check_lock();

                owner->a_session->swrite_l(B_FRAME);
                Flush();
                owner->a_session->sread_rect(&rect);
        }

        return rect;
}

As you can see we request from the server the frame rectangle, and Flush the
session. This means that for sure all our Frame modifications are processed
now, and the frame returned will be the one which the server has at the
moment. The notification of our changes will arrive after we finish the code
which comes after our Frame() call, but since we don't use it to cache local
data it doesn't matter, and the last notification will have the uptodate
data.

Example:

BRect ResizeAndReturnFrame()
{
        ResizeTo(200, 200);
        return Frame();
}

BView                   BSession                        ServerWindow

                        0                               Frame is 0, 0, 100, 100

ResizeTo 200, 200       B_RESIZETO                      Frame is 0, 0, 100, 100

Frame()                 B_FRAME, B_RESIZETO     Frame is 0, 0, 100, 100

<Frame() flushes>       0                               Frame is 0, 0, 200, 200 
<notification sent>

0, 0, 200, 200 returned 0                               Frame is 0, 0, 200, 200

back in dispatch loop we read the notification msg with 200, 200 and call
FrameResized(200, 200); There is no way that Frame() would return old data,
since all the commands wich do changes are processed. It is possible that
you get two notifications 0, 0, 100, 100 and 0, 0, 200, 200 if you resize
twice, in that case only the last one gives correct information. However if
in the loop you process all messages from the port, and then check in the
messagequeue for only the latest resize notification, you can drop the old
ones and only call the callback with the fresh information. This would match
with your experience, since after the Flush, you don't give back control to
the message loop, so the queue will contain two resize notifications, and
the callback is called once.

Marc Flerackers

> -----Original Message-----
> From: interfacekit-bounce@xxxxxxxxxxxxx
> [mailto:interfacekit-bounce@xxxxxxxxxxxxx]On Behalf Of Adi Oanca
> Sent: Monday, September 22, 2003 6:22 PM
> To: IK Team
> Subject: [interfacekit] sync
>
>
> Hello!
>
>     Marc, I need your idea on a very serious problem that I have.
>         [ I bet you were expecting this... :-) ]
>
>     It's about synchronization between app_server and BView class.
>     OK, what's this about?
>
>     Let's follow an example so you could understand better.
>
>     In BView::ResizeTo() I send to app_server a message, in turn it sends
> back the new width and height of that view, as well as the ones for its
> children. This is NOT a synchronous call! The server sends B_VIEW_RESIZED
> messages to window's server port to be dispatched through
> BWindow's message
> loop - like all other server messages.
>     The problem appears when I call BView::Frame() because it contacts
> app_server seeing that B_VIEW_COORD_BIT flag was set by BView::ResizeTo().
> This call is synchronous! It sends AS_LAYER_GET_COORDS msg to
> app_server and
> expects for them.
>     THE PROBLEM is app_server already sent some B_VIEW_RESIZED
> messages that
> have NOT been processed! ... and when BSession::ReadXXX tries to read the
> coordinates... it reads the WRONG data! - B_VIEW_RESIZED messages came
> first!
>
>     If I think a bit, I realize THIS is not the only time when
> de-synchronization appears! It's there EVERY time app_server sends a
> messages
> to BWindow/BView, e.g.. _UPDATE_ msg, and a synchronous call to app_server
> is
> made.
>
>     Haven't you encountered the same problem? How did you solved
> it? How did
> Be solved it!
>
>
> I have an idea about solving it! It involves prefixing each synchronous
> reply with an identifier(the same as the message name sent to server) and
> till the right reply arrives dispatch those before it!
>     The code looks like this:
>
>     BView::Frame(){
>         ...
>             session->WriteInt32( AS_LAYER_GET_COORDS );
>             session->Sync();
>
>             ensureRightReply( AS_LAYER_GET_COORDS );
>             session->ReadRect( &fBounds );
>             session->ReadFloat( &originX );
>             session->ReadFloat( &originY );
>         ...
>     }
>
>     BView::ensureRightReply( int32 code ){
>         int32        c;
>
>         session->ReadInt32( &c );
>         while( c != code ){
>             BMessage    *msg = NULL;
>
>             msg            = ConvertToMessage( c );
>             if ( msg )
>                 DispatchMessage( msg );
>
>             if ( msg )
>                 delete msg;
>         }
>     }
>
>
> PS: lots of BView::ResizeTo/By generate ONLY ONE
> BView::FrameResized()! How
> is this done? A flag is set and when in task_looper it is checked and a
> message sent if set?
>
>     I cannot think of another way since in:
> ====
>  ResizeTo(153.0f, 271.0f);
>  frame  = Frame();
>
>  printf("Applying ResizeTo(153.0, 271.0)...\n");
>  printf("\tFrame(): (%f,%f,%f,%f)\n", frame.left, frame.top, frame.right,
> frame.bottom);
>
>  Flush(); //Sync();
>
>  ResizeBy(11.0f, 6.0f);
>  frame  = Frame();
>
>  printf("Applying ResizeBy(11.0, 6.0)...\n");
>  printf("\tView1::Frame(): (%f,%f,%f,%f)\n", frame.left, frame.top,
> frame.right, frame.bottom);
> ===
>
>     BView::FrameResized() it's called once.
>
>
> Adi.
>
>
>
>


Other related posts: