On Mar 23, 2013, at 12:18 AM, Steve Mills wrote:

> On Mar 13, 2013, at 10:34:35, Ken Thomases <k...@codeweavers.com> wrote:
> 
>> The Window Server moves most windows entirely without involving the app 
>> (until the move is completed).  If you want to change how windows get moved, 
>> I think you have to take over the whole process.  You do [window 
>> setMovable:NO] to make the Window Server not move your windows itself.  
>> Instead, you get the relevant mouse events and you write typical mouse drag 
>> code and change the window frame manually.  See the docs for -[NSWindow 
>> isMovable].
> 
> I'm getting back to this now. The window being dragged is an NSPanel. I've 
> subclassed it so I could catch mouseDown, mouseDragged, and mouseUp. I also 
> return NO from isMovable.

Meaning you've overridden -isMovable?  Or did you call -setMovable: with NO?  I 
think you have to do the latter because that configures the Window Server's 
metadata about the window.  It might also configure the theme frame views (the 
framework-private views that make up the title bar, etc.) to behave 
differently.  So, basically, I think "movability" is a value that you have to 
set rather than something the frameworks and Window Server get by querying 
-isMovable.

> The problem is, when I click in the titlebar, neither mouseDown nor mouseUp 
> get called, only mouseDragged. This makes it impossible to know the starting 
> position so I can move the window. Seems like a bug. Is there any way to get 
> mouseDown and mouseUp in the titlebar?

I just did a test and confirm what you've described.  Then I rechecked the 
documentation of -isMovable and see that it says you have to handle the mouse 
down, drag, and up events inside of -sendEvent:.  Of course, it confuses 
matters by referring to those events by their responder method names, when it 
should have said "Applications may choose to enable application-controlled 
window dragging after disabling user-initiating dragging by handling the 
NSLeftMouseDown/NSLeftMouseDragged/NSLeftMouseUp sequence in sendEvent: in an 
NSWindow subclass."

I tested that approach and it works, of course.  -sendEvent: is what would 
dispatch those events to the theme frame views, but if you handle them directly 
there, instead, they won't get dispatched that way.  You have to be careful to 
still dispatch clicks inside the title bar's various widgets, or the user won't 
be able to, for example, close the window by clicking on its close button.

Here's an example which works.  It allows moving the window by its background 
(simply because it doesn't bother checking if the click is in the content view) 
and I haven't tested if it interferes with clicks in the actual title area 
(like pulling down the menu for a document), but it probably does.

// instance variables
    BOOL draggingWindow;
    NSPoint dragStart;
    NSPoint originAtDragStart;

- (BOOL) eventHitsWindowButton:(NSEvent*)event
{
    NSWindowButton buttons[] = {
        NSWindowCloseButton,
        NSWindowMiniaturizeButton,
        NSWindowZoomButton,
        NSWindowToolbarButton,
        NSWindowDocumentIconButton,
#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= 
MAC_OS_X_VERSION_10_7
        NSWindowDocumentVersionsButton,
        NSWindowFullScreenButton,
#endif
    };

    for (int i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++)
    {
        NSButton* button = [self standardWindowButton:buttons[i]];
        if ([button hitTest:[[button superview] convertPoint:[event 
locationInWindow] fromView:nil]])
            return TRUE;
    }

    return FALSE;
}

-(void) sendEvent:(NSEvent *)theEvent
{
    NSEventType type = [theEvent type];

    if (draggingWindow)
    {
        switch (type)
        {
            case NSLeftMouseDragged:
            {
                NSPoint dragLoc = [self convertBaseToScreen:[theEvent 
locationInWindow]];
                NSPoint newOrigin = originAtDragStart;
                newOrigin.x += dragLoc.x - dragStart.x;
                newOrigin.y += dragLoc.y - dragStart.y;
                [self setFrameOrigin:newOrigin];
                return;
            }
            case NSLeftMouseUp:
                draggingWindow = FALSE;
                return;
        }
    }
    else if (type == NSLeftMouseDown && ![self eventHitsWindowButton:theEvent])
    {
        draggingWindow = TRUE;
        dragStart = [self convertBaseToScreen:[theEvent locationInWindow]];
        originAtDragStart = [self frame].origin;
        return;
    }

    [super sendEvent:theEvent];
}


Cheers,
Ken


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to