mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-19 18:00:09 +00:00
66207cf13e
On X11 we receive enter notify and motion notify events for a window regardless of its focus state. On Mac OS X this is not the case. This commit improves the semantics to overcome this difference. It improves on my earlier patch that sent a motion notify event when a window became main. Instead of sending a motion notify when a window becomes main, we now send one when a window becomes key, which comes closest to a window getting focus in X11. This motion notify is needed because Mac OS X does not send motion events when an application is inactive (none of its windows have focus), these events are sent in X11. This dummy motion notify event (with current coordinates of the mouse cursor) allows an application to get its prelight and other state right when it gets focus and thus user attention. Another change is to send an enter notify event when updating the tracking rectangle of a GdkQuartView and the mouse cursor is currently in this rectangle. This rectangle is at least updated on window creation. This enter notify event is important for the case where a new window appears right below the mouse cursor. The window has to receive an enter notify event for the subsequent events to be processed correctly. Mac OS X does not send one in this case, so we generate it ourselves. Both of these synthesized events have to go through _gdk_windowing_got_event() for updating statekeeping, etc. append_event() has a boolean flag now to make this convenient.
209 lines
5.0 KiB
C
209 lines
5.0 KiB
C
/* GdkQuartzView.m
|
|
*
|
|
* Copyright (C) 2005-2007 Imendio AB
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
|
|
#import "GdkQuartzView.h"
|
|
#include "gdkwindow-quartz.h"
|
|
#include "gdkprivate-quartz.h"
|
|
|
|
@implementation GdkQuartzView
|
|
|
|
-(void)dealloc
|
|
{
|
|
if (trackingRect)
|
|
{
|
|
[self removeTrackingRect:trackingRect];
|
|
trackingRect = 0;
|
|
}
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)setGdkWindow:(GdkWindow *)window
|
|
{
|
|
gdk_window = window;
|
|
}
|
|
|
|
-(GdkWindow *)gdkWindow
|
|
{
|
|
return gdk_window;
|
|
}
|
|
|
|
-(NSTrackingRectTag)trackingRect
|
|
{
|
|
return trackingRect;
|
|
}
|
|
|
|
-(BOOL)isFlipped
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
-(BOOL)isOpaque
|
|
{
|
|
if (GDK_WINDOW_DESTROYED (gdk_window))
|
|
return YES;
|
|
|
|
/* A view is opaque if its GdkWindow doesn't have the RGBA colormap */
|
|
return gdk_drawable_get_colormap (gdk_window) != gdk_screen_get_rgba_colormap (_gdk_screen);
|
|
}
|
|
|
|
-(void)drawRect:(NSRect)rect
|
|
{
|
|
GdkRectangle gdk_rect;
|
|
GdkWindowObject *private = GDK_WINDOW_OBJECT (gdk_window);
|
|
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
|
|
const NSRect *drawn_rects;
|
|
NSInteger count;
|
|
int i;
|
|
GdkRegion *region;
|
|
|
|
if (GDK_WINDOW_DESTROYED (gdk_window))
|
|
return;
|
|
|
|
if (!(private->event_mask & GDK_EXPOSURE_MASK))
|
|
return;
|
|
|
|
if (NSEqualRects (rect, NSZeroRect))
|
|
return;
|
|
|
|
/* Clear our own bookkeeping of regions that need display */
|
|
if (impl->needs_display_region)
|
|
{
|
|
gdk_region_destroy (impl->needs_display_region);
|
|
impl->needs_display_region = NULL;
|
|
}
|
|
|
|
[self getRectsBeingDrawn:&drawn_rects count:&count];
|
|
|
|
/* Note: arbitrary limit here to not degrade performace too much. It would
|
|
* be better to optimize the construction of the region below, by using
|
|
* _gdk_region_new_from_yxbanded_rects.
|
|
*/
|
|
if (count > 25)
|
|
{
|
|
gdk_rect.x = rect.origin.x;
|
|
gdk_rect.y = rect.origin.y;
|
|
gdk_rect.width = rect.size.width;
|
|
gdk_rect.height = rect.size.height;
|
|
|
|
region = gdk_region_rectangle (&gdk_rect);
|
|
}
|
|
else
|
|
{
|
|
region = gdk_region_new ();
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
gdk_rect.x = drawn_rects[i].origin.x;
|
|
gdk_rect.y = drawn_rects[i].origin.y;
|
|
gdk_rect.width = drawn_rects[i].size.width;
|
|
gdk_rect.height = drawn_rects[i].size.height;
|
|
|
|
gdk_region_union_with_rect (region, &gdk_rect);
|
|
}
|
|
}
|
|
|
|
impl->in_paint_rect_count++;
|
|
_gdk_window_process_updates_recurse (gdk_window, region);
|
|
impl->in_paint_rect_count--;
|
|
|
|
gdk_region_destroy (region);
|
|
|
|
if (needsInvalidateShadow)
|
|
{
|
|
[[self window] invalidateShadow];
|
|
needsInvalidateShadow = NO;
|
|
}
|
|
}
|
|
|
|
-(void)setNeedsInvalidateShadow:(BOOL)invalidate
|
|
{
|
|
needsInvalidateShadow = invalidate;
|
|
}
|
|
|
|
/* For information on setting up tracking rects properly, see here:
|
|
* http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/EventOverview.pdf
|
|
*/
|
|
-(void)updateTrackingRect
|
|
{
|
|
GdkWindowObject *private = GDK_WINDOW_OBJECT (gdk_window);
|
|
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
|
|
NSRect rect;
|
|
|
|
if (!impl->toplevel)
|
|
return;
|
|
|
|
if (trackingRect)
|
|
{
|
|
[self removeTrackingRect:trackingRect];
|
|
trackingRect = 0;
|
|
}
|
|
|
|
if (!impl->toplevel)
|
|
return;
|
|
|
|
/* Note, if we want to set assumeInside we can use:
|
|
* NSPointInRect ([[self window] convertScreenToBase:[NSEvent mouseLocation]], rect)
|
|
*/
|
|
|
|
rect = [self bounds];
|
|
trackingRect = [self addTrackingRect:rect
|
|
owner:self
|
|
userData:nil
|
|
assumeInside:NO];
|
|
|
|
if (NSPointInRect ([[self window] convertScreenToBase:[NSEvent mouseLocation]], rect))
|
|
{
|
|
/* When a new window (and thus view) has been created, and the mouse
|
|
* is in the window area, we will not receive an NSMouseEntered
|
|
* event. Therefore, we synthesize an enter notify event manually.
|
|
*/
|
|
_gdk_quartz_events_send_enter_notify_event (gdk_window);
|
|
}
|
|
}
|
|
|
|
-(void)viewDidMoveToWindow
|
|
{
|
|
if (![self window]) /* We are destroyed already */
|
|
return;
|
|
|
|
[self updateTrackingRect];
|
|
}
|
|
|
|
-(void)viewWillMoveToWindow:(NSWindow *)newWindow
|
|
{
|
|
if (newWindow == nil && trackingRect)
|
|
{
|
|
[self removeTrackingRect:trackingRect];
|
|
trackingRect = 0;
|
|
}
|
|
}
|
|
|
|
-(void)setFrame:(NSRect)frame
|
|
{
|
|
[super setFrame:frame];
|
|
|
|
if ([self window])
|
|
[self updateTrackingRect];
|
|
}
|
|
|
|
@end
|