diff options
author | John Ralls <jralls@ceridwen.us> | 2010-12-24 11:25:40 -0800 |
---|---|---|
committer | John Ralls <jralls@ceridwen.us> | 2010-12-24 11:29:08 -0800 |
commit | 806b6dfa08db0cdaa7d0489e085337b143896ea4 (patch) | |
tree | f86fab7f846f98a476da0187c0dc0a880470631b /gdk/quartz/GdkQuartzNSWindow.c | |
parent | 0f0512aee3f18d4a160a87ec1ad9934aa459cbe1 (diff) | |
download | gtk+-806b6dfa08db0cdaa7d0489e085337b143896ea4.tar.gz |
Rename GdkQuartzWindow.h and .c to GdkQuartzNSWindow.h and .c
Normally HFS+ (the MacOSX file system) isn't case-sensitive, so having both
GtkQuartzWindow.h and gtkquartzwindow.h causes the latter to overwrite the
former during git pull, breaking the build.
Diffstat (limited to 'gdk/quartz/GdkQuartzNSWindow.c')
-rw-r--r-- | gdk/quartz/GdkQuartzNSWindow.c | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/gdk/quartz/GdkQuartzNSWindow.c b/gdk/quartz/GdkQuartzNSWindow.c new file mode 100644 index 0000000000..ee21797383 --- /dev/null +++ b/gdk/quartz/GdkQuartzNSWindow.c @@ -0,0 +1,598 @@ +/* GdkQuartzWindow.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 "GdkQuartzNSWindow.h" +#include "gdkquartzwindow.h" +#include "gdkdnd-quartz.h" +#include "gdkprivate-quartz.h" + +@implementation GdkQuartzNSWindow + +-(BOOL)windowShouldClose:(id)sender +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkEvent *event; + + event = gdk_event_new (GDK_DELETE); + + event->any.window = g_object_ref (window); + event->any.send_event = FALSE; + + _gdk_event_queue_append (gdk_display_get_default (), event); + + return NO; +} + +-(void)windowWillMiniaturize:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + _gdk_quartz_window_detach_from_parent (window); +} + +-(void)windowDidMiniaturize:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + gdk_synthesize_window_state (window, 0, + GDK_WINDOW_STATE_ICONIFIED); +} + +-(void)windowDidDeminiaturize:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + _gdk_quartz_window_attach_to_parent (window); + + gdk_synthesize_window_state (window, GDK_WINDOW_STATE_ICONIFIED, 0); +} + +-(void)windowDidBecomeKey:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + _gdk_quartz_events_update_focus_window (window, TRUE); +} + +-(void)windowDidResignKey:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + _gdk_quartz_events_update_focus_window (window, FALSE); +} + +-(void)windowDidBecomeMain:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + + if (![self isVisible]) + { + /* Note: This is a hack needed because for unknown reasons, hidden + * windows get shown when clicking the dock icon when the application + * is not already active. + */ + [self orderOut:nil]; + return; + } + + _gdk_quartz_window_did_become_main (window); +} + +-(void)windowDidResignMain:(NSNotification *)aNotification +{ + GdkWindow *window; + + window = [[self contentView] gdkWindow]; + _gdk_quartz_window_did_resign_main (window); +} + +/* Used in combination with NSLeftMouseUp in sendEvent to keep track + * of when the window is being moved with the mouse. + */ +-(void)windowWillMove:(NSNotification *)aNotification +{ + inMove = YES; +} + +-(void)sendEvent:(NSEvent *)event +{ + switch ([event type]) + { + case NSLeftMouseUp: + inManualMove = NO; + inManualResize = NO; + inMove = NO; + break; + + case NSLeftMouseDragged: + if ([self trackManualMove] || [self trackManualResize]) + return; + break; + + default: + break; + } + + [super sendEvent:event]; +} + +-(BOOL)isInMove +{ + return inMove; +} + +-(void)windowDidMove:(NSNotification *)aNotification +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkEvent *event; + + _gdk_quartz_window_update_position (window); + + /* Synthesize a configure event */ + event = gdk_event_new (GDK_CONFIGURE); + event->configure.window = g_object_ref (window); + event->configure.x = window->x; + event->configure.y = window->y; + event->configure.width = window->width; + event->configure.height = window->height; + + _gdk_event_queue_append (gdk_display_get_default (), event); +} + +-(void)windowDidResize:(NSNotification *)aNotification +{ + NSRect content_rect = [self contentRectForFrameRect:[self frame]]; + GdkWindow *window = [[self contentView] gdkWindow]; + GdkEvent *event; + + window->width = content_rect.size.width; + window->height = content_rect.size.height; + + [[self contentView] setFrame:NSMakeRect (0, 0, window->width, window->height)]; + + _gdk_window_update_size (window); + + /* Synthesize a configure event */ + event = gdk_event_new (GDK_CONFIGURE); + event->configure.window = g_object_ref (window); + event->configure.x = window->x; + event->configure.y = window->y; + event->configure.width = window->width; + event->configure.height = window->height; + + _gdk_event_queue_append (gdk_display_get_default (), event); +} + +-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag screen:(NSScreen *)screen +{ + self = [super initWithContentRect:contentRect + styleMask:styleMask + backing:backingType + defer:flag + screen:screen]; + + [self setAcceptsMouseMovedEvents:YES]; + [self setDelegate:self]; + [self setReleasedWhenClosed:YES]; + + return self; +} + +-(BOOL)canBecomeMainWindow +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl); + + switch (impl->type_hint) + { + case GDK_WINDOW_TYPE_HINT_NORMAL: + case GDK_WINDOW_TYPE_HINT_DIALOG: + return YES; + + case GDK_WINDOW_TYPE_HINT_MENU: + case GDK_WINDOW_TYPE_HINT_TOOLBAR: + case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN: + case GDK_WINDOW_TYPE_HINT_UTILITY: + case GDK_WINDOW_TYPE_HINT_DOCK: + case GDK_WINDOW_TYPE_HINT_DESKTOP: + case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: + case GDK_WINDOW_TYPE_HINT_POPUP_MENU: + case GDK_WINDOW_TYPE_HINT_TOOLTIP: + case GDK_WINDOW_TYPE_HINT_NOTIFICATION: + case GDK_WINDOW_TYPE_HINT_COMBO: + case GDK_WINDOW_TYPE_HINT_DND: + return NO; + } + + return YES; +} + +-(BOOL)canBecomeKeyWindow +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl); + + if (!window->accept_focus) + return NO; + + /* Popup windows should not be able to get focused in the window + * manager sense, it's only handled through grabs. + */ + if (window->window_type == GDK_WINDOW_TEMP) + return NO; + + switch (impl->type_hint) + { + case GDK_WINDOW_TYPE_HINT_NORMAL: + case GDK_WINDOW_TYPE_HINT_DIALOG: + case GDK_WINDOW_TYPE_HINT_MENU: + case GDK_WINDOW_TYPE_HINT_TOOLBAR: + case GDK_WINDOW_TYPE_HINT_UTILITY: + case GDK_WINDOW_TYPE_HINT_DOCK: + case GDK_WINDOW_TYPE_HINT_DESKTOP: + case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: + case GDK_WINDOW_TYPE_HINT_POPUP_MENU: + case GDK_WINDOW_TYPE_HINT_COMBO: + return YES; + + case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN: + case GDK_WINDOW_TYPE_HINT_TOOLTIP: + case GDK_WINDOW_TYPE_HINT_NOTIFICATION: + case GDK_WINDOW_TYPE_HINT_DND: + return NO; + } + + return YES; +} + +- (void)showAndMakeKey:(BOOL)makeKey +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl); + + inShowOrHide = YES; + + if (makeKey) + [impl->toplevel makeKeyAndOrderFront:impl->toplevel]; + else + [impl->toplevel orderFront:nil]; + + inShowOrHide = NO; +} + +- (void)hide +{ + GdkWindow *window = [[self contentView] gdkWindow]; + GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl); + + inShowOrHide = YES; + [impl->toplevel orderOut:nil]; + inShowOrHide = NO; +} + +- (BOOL)trackManualMove +{ + NSPoint currentLocation; + NSPoint newOrigin; + NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; + NSRect windowFrame = [self frame]; + + if (!inManualMove) + return NO; + + currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]]; + newOrigin.x = currentLocation.x - initialMoveLocation.x; + newOrigin.y = currentLocation.y - initialMoveLocation.y; + + /* Clamp vertical position to below the menu bar. */ + if (newOrigin.y + windowFrame.size.height > screenFrame.origin.y + screenFrame.size.height) + newOrigin.y = screenFrame.origin.y + screenFrame.size.height - windowFrame.size.height; + + [self setFrameOrigin:newOrigin]; + + return YES; +} + +-(void)beginManualMove +{ + NSRect frame = [self frame]; + + if (inMove || inManualMove || inManualResize) + return; + + inManualMove = YES; + + initialMoveLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]]; + initialMoveLocation.x -= frame.origin.x; + initialMoveLocation.y -= frame.origin.y; +} + +- (BOOL)trackManualResize +{ + NSPoint currentLocation; + NSRect newFrame; + float dx, dy; + NSSize min_size; + + if (!inManualResize || inTrackManualResize) + return NO; + + inTrackManualResize = YES; + + currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]]; + currentLocation.x -= initialResizeFrame.origin.x; + currentLocation.y -= initialResizeFrame.origin.y; + + dx = currentLocation.x - initialResizeLocation.x; + dy = -(currentLocation.y - initialResizeLocation.y); + + newFrame = initialResizeFrame; + newFrame.size.width = initialResizeFrame.size.width + dx; + newFrame.size.height = initialResizeFrame.size.height + dy; + + min_size = [self contentMinSize]; + if (newFrame.size.width < min_size.width) + newFrame.size.width = min_size.width; + if (newFrame.size.height < min_size.height) + newFrame.size.height = min_size.height; + + /* We could also apply aspect ratio: + newFrame.size.height = newFrame.size.width / [self aspectRatio].width * [self aspectRatio].height; + */ + + dy = newFrame.size.height - initialResizeFrame.size.height; + + newFrame.origin.x = initialResizeFrame.origin.x; + newFrame.origin.y = initialResizeFrame.origin.y - dy; + + [self setFrame:newFrame display:YES]; + + /* Let the resizing be handled by GTK+. */ + if (g_main_context_pending (NULL)) + g_main_context_iteration (NULL, FALSE); + + inTrackManualResize = NO; + + return YES; +} + +-(void)beginManualResize +{ + if (inMove || inManualMove || inManualResize) + return; + + inManualResize = YES; + + initialResizeFrame = [self frame]; + initialResizeLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]]; + initialResizeLocation.x -= initialResizeFrame.origin.x; + initialResizeLocation.y -= initialResizeFrame.origin.y; +} + + + +static GdkDragContext *current_context = NULL; + +static GdkDragAction +drag_operation_to_drag_action (NSDragOperation operation) +{ + GdkDragAction result = 0; + + /* GDK and Quartz drag operations do not map 1:1. + * This mapping represents about the best that we + * can come up. + * + * Note that NSDragOperationPrivate and GDK_ACTION_PRIVATE + * have almost opposite meanings: the GDK one means that the + * destination is solely responsible for the action; the Quartz + * one means that the source and destination will agree + * privately on the action. NSOperationGeneric is close in meaning + * to GDK_ACTION_PRIVATE but there is a problem: it will be + * sent for any ordinary drag, and likely not understood + * by any intra-widget drag (since the source & dest are the + * same). + */ + + if (operation & NSDragOperationGeneric) + result |= GDK_ACTION_MOVE; + if (operation & NSDragOperationCopy) + result |= GDK_ACTION_COPY; + if (operation & NSDragOperationMove) + result |= GDK_ACTION_MOVE; + if (operation & NSDragOperationLink) + result |= GDK_ACTION_LINK; + + return result; +} + +static NSDragOperation +drag_action_to_drag_operation (GdkDragAction action) +{ + NSDragOperation result = 0; + + if (action & GDK_ACTION_COPY) + result |= NSDragOperationCopy; + if (action & GDK_ACTION_LINK) + result |= NSDragOperationLink; + if (action & GDK_ACTION_MOVE) + result |= NSDragOperationMove; + + return result; +} + +static void +update_context_from_dragging_info (id <NSDraggingInfo> sender) +{ + g_assert (current_context != NULL); + + GDK_QUARTZ_DRAG_CONTEXT (current_context)->dragging_info = sender; + current_context->suggested_action = drag_operation_to_drag_action ([sender draggingSourceOperationMask]); + current_context->actions = current_context->suggested_action; +} + +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender +{ + GdkDeviceManager *device_manager; + GdkEvent *event; + GdkWindow *window; + + if (current_context) + g_object_unref (current_context); + + current_context = g_object_new (GDK_TYPE_QUARTZ_DRAG_CONTEXT, NULL); + update_context_from_dragging_info (sender); + + window = [[self contentView] gdkWindow]; + + device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); + gdk_drag_context_set_device (current_context, + gdk_device_manager_get_client_pointer (device_manager)); + + event = gdk_event_new (GDK_DRAG_ENTER); + event->dnd.window = g_object_ref (window); + event->dnd.send_event = FALSE; + event->dnd.context = g_object_ref (current_context); + event->dnd.time = GDK_CURRENT_TIME; + + gdk_event_set_device (event, gdk_drag_context_get_device (current_context)); + + _gdk_event_emit (event); + + gdk_event_free (event); + + return NSDragOperationNone; +} + +- (void)draggingEnded:(id <NSDraggingInfo>)sender +{ + /* leave a note for the source about what action was taken */ + if (_gdk_quartz_drag_source_context && current_context) + _gdk_quartz_drag_source_context->action = current_context->action; + + if (current_context) + g_object_unref (current_context); + current_context = NULL; +} + +- (void)draggingExited:(id <NSDraggingInfo>)sender +{ + GdkEvent *event; + + event = gdk_event_new (GDK_DRAG_LEAVE); + event->dnd.window = g_object_ref ([[self contentView] gdkWindow]); + event->dnd.send_event = FALSE; + event->dnd.context = g_object_ref (current_context); + event->dnd.time = GDK_CURRENT_TIME; + + gdk_event_set_device (event, gdk_drag_context_get_device (current_context)); + + _gdk_event_emit (event); + + gdk_event_free (event); + + g_object_unref (current_context); + current_context = NULL; +} + +- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender +{ + NSPoint point = [sender draggingLocation]; + NSPoint screen_point = [self convertBaseToScreen:point]; + GdkEvent *event; + int gx, gy; + + update_context_from_dragging_info (sender); + _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &gx, &gy); + + event = gdk_event_new (GDK_DRAG_MOTION); + event->dnd.window = g_object_ref ([[self contentView] gdkWindow]); + event->dnd.send_event = FALSE; + event->dnd.context = g_object_ref (current_context); + event->dnd.time = GDK_CURRENT_TIME; + event->dnd.x_root = gx; + event->dnd.y_root = gy; + + gdk_event_set_device (event, gdk_drag_context_get_device (current_context)); + + _gdk_event_emit (event); + + gdk_event_free (event); + + return drag_action_to_drag_operation (current_context->action); +} + +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender +{ + NSPoint point = [sender draggingLocation]; + NSPoint screen_point = [self convertBaseToScreen:point]; + GdkEvent *event; + int gy, gx; + + update_context_from_dragging_info (sender); + _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &gx, &gy); + + event = gdk_event_new (GDK_DROP_START); + event->dnd.window = g_object_ref ([[self contentView] gdkWindow]); + event->dnd.send_event = FALSE; + event->dnd.context = g_object_ref (current_context); + event->dnd.time = GDK_CURRENT_TIME; + event->dnd.x_root = gx; + event->dnd.y_root = gy; + + gdk_event_set_device (event, gdk_drag_context_get_device (current_context)); + + _gdk_event_emit (event); + + gdk_event_free (event); + + g_object_unref (current_context); + current_context = NULL; + + return YES; +} + +- (BOOL)wantsPeriodicDraggingUpdates +{ + return NO; +} + +- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation +{ + GdkEvent *event; + + g_assert (_gdk_quartz_drag_source_context != NULL); + + event = gdk_event_new (GDK_DROP_FINISHED); + event->dnd.window = g_object_ref ([[self contentView] gdkWindow]); + event->dnd.send_event = FALSE; + event->dnd.context = g_object_ref (_gdk_quartz_drag_source_context); + + gdk_event_set_device (event, + gdk_drag_context_get_device (_gdk_quartz_drag_source_context)); + + _gdk_event_emit (event); + + gdk_event_free (event); + + g_object_unref (_gdk_quartz_drag_source_context); + _gdk_quartz_drag_source_context = NULL; +} + +@end |