static gboolean
test_resize (NSEvent *event,
GdkMacosSurface *surface, int x, int y)
{
g_assert (event != NULL);
g_assert (GDK_IS_MACOS_SURFACE (surface));
/* If we're on Lion and within 5 pixels of an edge, then assume that the *userwantstoresize,andreturnNULLtoletQuartzgetonwithit. * *Weperformthischeckforabuttonpressofallbuttons,becausewe *doreceive,forinstance,arightmousedowneventforaGDKsurface *forx-coordinaterange[-3,0],butwedonotwanttoforwardthis *intoGDK.ForwardingsucheventsintoGDKwillconfusethepointer *windowfindingcode,becausetherearenoGdkSurfacespresentin *therange[-3,0].
*/ if (([event type] == NSEventTypeLeftMouseDown ||
[event type] == NSEventTypeRightMouseDown ||
[event type] == NSEventTypeOtherMouseDown))
{ if (x < GDK_LION_RESIZE ||
x > GDK_SURFACE (surface)->width - GDK_LION_RESIZE ||
y > GDK_SURFACE (surface)->height - GDK_LION_RESIZE) returnTRUE;
}
returnFALSE;
}
static guint32
get_time_from_ns_event (NSEvent *event)
{ double time = [event timestamp]; /* cast via double->uint64 conversion to make sure that it is *wrappedon32-bitmachineswhenitoverflows
*/ return (guint32) (guint64) (time * 1000.0);
}
switch ((int)[nsevent type])
{ case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown:
type = GDK_BUTTON_PRESS;
state &= ~get_mouse_button_modifiers_from_ns_event (nsevent); break;
case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp:
type = GDK_BUTTON_RELEASE;
state |= get_mouse_button_modifiers_from_ns_event (nsevent); break;
default:
g_assert_not_reached ();
}
/* Ignore button press events outside the window coords but *allowforbuttonreleasewhichcanhappenduringgrabs.
*/ if (type == GDK_BUTTON_PRESS &&
(x < 0 || x > GDK_SURFACE (surface)->width ||
y < 0 || y > GDK_SURFACE (surface)->height ||
(input_region && !cairo_region_contains_point (input_region, x, y)))) return NULL;
/* Ignore button press events that happen on a native window button. *Forthoseeventswedonotreceiveabuttonreleaseeventwhichleaves *ourappina"grabbed"state.
*/ if (type == GDK_BUTTON_PRESS && over_native_window_buttons (nsevent))
{
GDK_DEBUG (EVENTS, "Ignoring button press over native controls (%d, %d)", x, y); return NULL;
}
/* If the key press is a modifier, the state should include the mask for *thatmodifierbutonlyforreleases,notpresses.Thismatchesthe *X11backendbehavior.
*/ if (is_modifier)
{
guint mask = 0;
switch (keyval)
{ case GDK_KEY_Meta_R: case GDK_KEY_Meta_L:
mask = GDK_META_MASK; break; case GDK_KEY_Shift_R: case GDK_KEY_Shift_L:
mask = GDK_SHIFT_MASK; break; case GDK_KEY_Caps_Lock:
mask = GDK_LOCK_MASK; break; case GDK_KEY_Alt_R: case GDK_KEY_Alt_L:
mask = GDK_ALT_MASK; break; case GDK_KEY_Control_R: case GDK_KEY_Control_L:
mask = GDK_CONTROL_MASK; break; default:
mask = 0;
}
if (type == GDK_KEY_PRESS)
state &= ~mask; elseif (type == GDK_KEY_RELEASE)
state |= mask;
}
state |= _gdk_macos_display_get_current_mouse_modifiers (display);
/* fill_pinch_event handles the conversion from the two OSX gesture events *NSEventTypeMagnfiyandNSEventTypeRotatetotheGDK_TOUCHPAD_PINCHevent. *ThenormalbehavioroftheOSXeventsisthattheyproduceassequenceof *1xNSEventPhaseBegan, *nxNSEventPhaseChanged, *1xNSEventPhaseEnded *ThiscanhappenforboththeMagnifyandtheRotateeventsindependently. *AsbotheventsaresummarizedinoneGDK_TOUCHPAD_PINCHeventsequence,a *littlestatemachinehandlesthecaseoftwoNSEventPhaseBeganeventsin *asequence,e.g.Magnify(Began),Magnify(Changed)...,Rotate(Began)... *suchthatPINCH(STARTED),PINCH(UPDATE)....willnotshowasecond *PINCH(STARTED)event.
*/
switch ((int)[nsevent phase])
{ case NSEventPhaseBegan: switch (last_state)
{ case FP_STATE_IDLE:
phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
last_state = FP_STATE_UPDATE;
last_scale = 1.0; break; case FP_STATE_UPDATE: /* We have already received a PhaseBegan event but no PhaseEnded event.Thiscanhappen,e.g.Magnify(Began),Magnify(Change)... Rotate(Began),Rotate(Change),....,Magnify(End)Rotate(End)
*/
phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE; break;
} break;
case NSEventPhaseChanged:
phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE; break;
case NSEventPhaseEnded:
phase = GDK_TOUCHPAD_GESTURE_PHASE_END; switch (last_state)
{ case FP_STATE_IDLE: /* We are idle but have received a second PhaseEnded event. ThiscanhappenbecausewehaveMagnifyandRotateOSX eventsequences.WejustsendasecondendGDK_PHASE_END.
*/ break; case FP_STATE_UPDATE:
last_state = FP_STATE_IDLE; break;
} break;
case NSEventPhaseCancelled:
phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
last_state = FP_STATE_IDLE; break;
case NSEventPhaseMayBegin: case NSEventPhaseStationary:
phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL; break;
/* Ignore kinetic scroll events from the display server as we already *handlethoseinternally.
*/ if (phase == 0 && momentumPhase != 0) return GDK_MACOS_EVENT_DROP;
/* If we are starting a new phase, send a stop so any previous *scrollingimmediatelystops.
*/ if (phase == NSEventPhaseMayBegin) return gdk_scroll_event_new (GDK_SURFACE (surface),
pointer,
NULL,
get_time_from_ns_event (nsevent),
state, 0.0, 0.0, TRUE,
GDK_SCROLL_UNIT_SURFACE,
relative_direction);
dx = [nsevent deltaX];
dy = [nsevent deltaY];
if ([nsevent hasPreciseScrollingDeltas])
{ double sx; double sy;
sx = [nsevent scrollingDeltaX];
sy = [nsevent scrollingDeltaY];
if (sx != 0.0 || sy != 0.0)
ret = gdk_scroll_event_new (GDK_SURFACE (surface),
pointer,
NULL,
get_time_from_ns_event (nsevent),
state,
-sx,
-sy, FALSE,
GDK_SCROLL_UNIT_SURFACE,
relative_direction);
/* Fall through for scroll emulation */
}
if (dy != 0.0)
{ if (dy < 0.0)
direction = GDK_SCROLL_DOWN; else
direction = GDK_SCROLL_UP;
dx = 0.0;
} elseif (dx != 0.0)
{ if (dx < 0.0)
direction = GDK_SCROLL_RIGHT; else
direction = GDK_SCROLL_LEFT;
dy = 0.0;
}
if ((dx != 0.0 || dy != 0.0) && ![nsevent hasPreciseScrollingDeltas])
{
g_assert (ret == NULL);
if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled)
{ /* The user must have released their fingers in a touchpad *scroll,sotrytosendascrollis_stopevent.
*/ if (ret != NULL)
_gdk_event_queue_append (GDK_DISPLAY (self), g_steal_pointer (&ret));
ret = gdk_scroll_event_new (GDK_SURFACE (surface),
pointer,
NULL,
get_time_from_ns_event (nsevent),
state, 0.0, 0.0, TRUE,
GDK_SCROLL_UNIT_SURFACE,
relative_direction);
}
return g_steal_pointer (&ret);
}
static GdkEvent *
fill_event (GdkMacosDisplay *self,
GdkMacosSurface *surface,
NSEvent *nsevent, int x, int y,
gboolean in_manual_resize_or_move)
{
NSEventType event_type = [nsevent type];
GdkEvent *ret = NULL;
switch ((int)event_type)
{ case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp:
ret = fill_button_event (self, surface, nsevent, x, y); break;
case NSEventTypeLeftMouseDragged: case NSEventTypeRightMouseDragged: case NSEventTypeOtherMouseDragged: case NSEventTypeMouseMoved:
ret = fill_motion_event (self, surface, nsevent, x, y); break;
case NSEventTypeMagnify: case NSEventTypeRotate:
ret = fill_pinch_event (self, surface, nsevent, x, y); break;
case NSEventTypeMouseExited: case NSEventTypeMouseEntered:
{
GdkSeat *seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
GdkDevice *pointer = gdk_seat_get_pointer (seat);
if (in_manual_resize_or_move)
{
ret = GDK_MACOS_EVENT_DROP;
} elseif (!gdk_macos_device_get_implicit_grab (pointer))
{ if (event_type == NSEventTypeMouseExited)
[[NSCursor arrowCursor] set];
ret = synthesize_crossing_event (self, surface, nsevent, x, y);
}
}
break;
case NSEventTypeKeyDown: case NSEventTypeKeyUp: case NSEventTypeFlagsChanged: {
GdkEventType type = _gdk_macos_keymap_get_event_type (nsevent);
if (type)
ret = fill_key_event (self, surface, nsevent, type);
break;
}
case NSEventTypeScrollWheel:
ret = fill_scroll_event (self, surface, nsevent, x, y); break;
default: break;
}
return ret;
}
static gboolean
is_mouse_button_press_event (NSEventType type)
{ switch ((int)type)
{ case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: returnTRUE;
default: returnFALSE;
}
}
staticvoid
get_surface_point_from_screen_point (GdkMacosDisplay *self,
GdkMacosSurface *surface,
NSPoint screen_point, int *x, int *y)
{ int x_tmp, y_tmp;
/* NSEvents come in with a window set, but with window coordinates *outofwindowbounds.Fore.g.movedeventsthisisfine,weuse *thisinformationtoproperlyhandleenter/leavenotifyandmotion *events.Formousebuttonpress/release,wewanttoavoidforwarding *theseeventshowever,becausethewindowtheyrelatetoisnotthe *windowsetintheevent.Thissituationappearstooccurwhenbutton *pressescomeinjustbefore(orjustafter?)awindowisresizedand *alsowhenabuttonpressoccursontheOSXwindowtitlebar. * *BysettingsurfacetoNULL,wedoanotherattempttogettheright *surfacewindowbelow.
*/ if (is_mouse_button_press_event ([nsevent type]) &&
(view_point.x < view_frame.origin.x ||
view_point.x >= view_frame.origin.x + view_frame.size.width ||
view_point.y < view_frame.origin.y ||
view_point.y >= view_frame.origin.y + view_frame.size.height))
{
NSRect windowRect = [nswindow frame];
surface = NULL;
/* This is a hack for button presses to break all grabs. E.g. if *amenuisopenandoneclicksonthetitlebar(oranywhere *outofwindowbounds),wereallywanttopopdownthemenu(by *breakingthegrabs)beforeOSXhandlestheactionofthetitle *barbutton. * *BecausewecannotingestthiseventintoGDK,wehavetodoit *here,notverynice.
*/
_gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent));
/* If the X,Y is on the frame itself, then we don't want to discover *thesurfaceunderthepointeratallsothatweletOSXhandle *itinstead.Weaddpaddingtoincluderesizeoperationstoo.
*/
windowRect.origin.x = -GDK_LION_RESIZE;
windowRect.origin.y = -GDK_LION_RESIZE;
windowRect.size.width += (2 * GDK_LION_RESIZE);
windowRect.size.height += (2 * GDK_LION_RESIZE); if (NSPointInRect (point, windowRect)) return NULL;
} else
{
*screen_point = convert_nspoint_to_screen ([nsevent window], point);
*x = point.x;
*y = surface->height - point.y;
}
}
find_under_pointer:
if (surface == NULL && nswindow == NULL)
{ /* Fallback used when no NSWindow set. This happens e.g. when *weallowmotioneventswithoutawindowsetingdk_event_translate() *thatoccurimmediatelyafterthemainmenubarwasclicked/used. *Thisfallbackwillnotreturncoordinatescontainedinawindow's *titlebar.
*/
*screen_point = [NSEvent mouseLocation];
surface = find_surface_under_pointer (self, *screen_point, x, y);
}
/* Even if we had a surface window, it might be for something outside *theinputregion(shadow)whichwemightwanttoignore.Thisis *handledforusdeeperintheeventunwrapping.
*/ if (!(surface = get_surface_from_ns_event (self, nsevent, &point, x, y))) return NULL;
if (implicit_grab_surface)
{
get_surface_point_from_screen_point (self, implicit_grab_surface, point, x, y); return implicit_grab_surface;
} elseif (grab_surface)
{ /* For owner events, we need to use the surface under the *pointer,notthewindowfromtheNSEvent,sincethatis *reportedwithrespecttothekeywindow,whichcouldbe *wrong.
*/
GdkSurface *surface_under_pointer; int x_tmp, y_tmp;
surface_under_pointer = find_surface_under_pointer (self, point, &x_tmp, &y_tmp); if (surface_under_pointer)
{
surface = surface_under_pointer;
*x = x_tmp;
*y = y_tmp;
}
return GDK_MACOS_SURFACE (surface);
} else
{ /* The non-grabbed case. */
GdkSurface *surface_under_pointer; int x_tmp, y_tmp;
/* Ignore all events but mouse moved that might be on the title *bar(abovethecontentview).Thereasonisthatotherwise *gdkgetsconfusedaboutgettinge.g.buttonpresseswithno *window(thetitlebarisnotknowntoit).
*/ if (event_type != NSEventTypeMouseMoved)
{ if (*y < 0) return NULL;
}
/* As for owner events, we need to use the surface under the *pointer,notthewindowfromtheNSEvent.
*/
surface_under_pointer = find_surface_under_pointer (self, point, &x_tmp, &y_tmp); if (surface_under_pointer != NULL)
{
surface = surface_under_pointer;
*x = x_tmp;
*y = y_tmp;
}
return GDK_MACOS_SURFACE (surface);
}
return NULL;
}
/* This function finds the correct window to send an event to, taking *intoaccountgrabs,eventpropagation,andeventmasks.
*/ static GdkMacosSurface *
find_surface_for_ns_event (GdkMacosDisplay *self,
NSEvent *nsevent, int *x, int *y)
{
GdkMacosBaseView *view;
GdkSurface *surface;
NSPoint point;
switch ((int)[nsevent type])
{ case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: case NSEventTypeLeftMouseDragged: case NSEventTypeRightMouseDragged: case NSEventTypeOtherMouseDragged: case NSEventTypeMouseMoved: case NSEventTypeScrollWheel: case NSEventTypeMagnify: case NSEventTypeRotate: return find_surface_for_mouse_event (self, nsevent, x, y);
case NSEventTypeMouseEntered: case NSEventTypeMouseExited: /* Only handle our own entered/exited events, not the ones for the *titlebarbuttons.
*/ if ((surface = get_surface_from_ns_event (self, nsevent, &point, x, y)) &&
(view = (GdkMacosBaseView *)[GDK_MACOS_SURFACE (surface)->window contentView]) &&
([nsevent trackingArea] == [view trackingArea])) return GDK_MACOS_SURFACE (surface); else return NULL;
case NSEventTypeKeyDown: case NSEventTypeKeyUp: case NSEventTypeFlagsChanged: return find_surface_for_keyboard_event (nsevent);
/* There is no support for real desktop wide grabs, so we break *grabswhentheapplicationlosesfocus(getsdeactivated).
*/
event_type = [nsevent type]; if (event_type == NSEventTypeAppKitDefined)
{ if ([nsevent subtype] == NSEventSubtypeApplicationDeactivated)
_gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent));
/* This could potentially be used to break grabs when clicking *onthetitle.Thesubtype20isundocumentedsoit'sprobably *notagoodidea:elseif(subtype==20)break_all_grabs();
*/
/* Leave all AppKit events to AppKit. */ return NULL;
}
/* We need to register the proximity event from any point on the screen *toproperlyregisterthedevices *FIXME:isthereabetterwaytodetectifatablethasbeenplugged?
*/ if (event_type == NSEventTypeTabletProximity)
{
GdkSeat *seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
/* FIXME: we might want to cache this proximity event and propagate it *butproximityeventsingdkworkatawindowlevelwhileonmacos *worksatascreenlevel.Fornowwejustskipthem.
*/ return NULL;
}
/* If the event was delivered to NSWindow that is foreign (or rather, *Cocoanative),thenweshouldpasstheeventalongtothatwindow.
*/ if ((event_window = [nsevent window]) && !GDK_IS_MACOS_WINDOW (event_window)) return NULL;
/* If we can't find a GdkSurface to deliver the event to, then we *shouldpassitalongtotheNSApp.
*/ if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y))) return NULL;
/* Ignore events and break grabs while the window is being *dragged.Thisisaworkaroundforthewindowgettingeventsfor *thewindowtitle.
*/ if ([window isInMove])
{
_gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent)); return NULL;
}
/* Also when in a manual resize or move , we ignore events so that *thesearepushedtoGdkMacosNSWindow'ssendEventhandler.
*/ if ([window isInManualResizeOrMove]) return NULL;
/* Make sure we have a GdkSurface */ if (!(surface = [window gdkSurface])) return NULL;
/* Quartz handles resizing on its own, so stay out of the way. */ if (test_resize (nsevent, surface, x, y)) return NULL;
if (event_type == NSEventTypeRightMouseDown ||
event_type == NSEventTypeOtherMouseDown ||
event_type == NSEventTypeLeftMouseDown)
{ if (![NSApp isActive])
[NSApp activateIgnoringOtherApps:YES];
if (![window isKeyWindow])
{
NSWindow *orig_window = [nsevent window];
/* To get NSApp to supress activating the window we might *haveclickedthroughtheshadowof,weneedtodispatch *theeventandhandleitinGdkMacosView:mouseDowntocall *[NSApppreventWindowOrdering].Callingitherewillnot *doanythingastheeventisnotregistered.
*/ if (orig_window &&
GDK_IS_MACOS_WINDOW (orig_window) &&
[(GdkMacosWindow *)orig_window needsMouseDownQuirk])
[NSApp sendEvent:nsevent];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.