3 * Copyright (C) 2005-2007 Imendio AB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #import "GdkQuartzWindow.h"
22 #include "gdkwindow-quartz.h"
23 #include "gdkprivate-quartz.h"
25 @implementation GdkQuartzWindow
27 -(BOOL)windowShouldClose:(id)sender
29 GdkWindow *window = [[self contentView] gdkWindow];
32 event = gdk_event_new (GDK_DELETE);
34 event->any.window = g_object_ref (window);
35 event->any.send_event = FALSE;
37 _gdk_event_queue_append (gdk_display_get_default (), event);
42 -(void)windowWillMiniaturize:(NSNotification *)aNotification
44 GdkWindow *window = [[self contentView] gdkWindow];
46 _gdk_quartz_window_detach_from_parent (window);
49 -(void)windowDidMiniaturize:(NSNotification *)aNotification
51 GdkWindow *window = [[self contentView] gdkWindow];
53 gdk_synthesize_window_state (window, 0,
54 GDK_WINDOW_STATE_ICONIFIED);
57 -(void)windowDidDeminiaturize:(NSNotification *)aNotification
59 GdkWindow *window = [[self contentView] gdkWindow];
61 _gdk_quartz_window_attach_to_parent (window);
63 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_ICONIFIED, 0);
66 -(void)windowDidBecomeKey:(NSNotification *)aNotification
68 GdkWindow *window = [[self contentView] gdkWindow];
70 _gdk_quartz_events_update_focus_window (window, TRUE);
73 -(void)windowDidResignKey:(NSNotification *)aNotification
75 GdkWindow *window = [[self contentView] gdkWindow];
77 _gdk_quartz_events_update_focus_window (window, FALSE);
80 -(void)windowDidBecomeMain:(NSNotification *)aNotification
82 GdkWindow *window = [[self contentView] gdkWindow];
84 if (![self isVisible])
86 /* Note: This is a hack needed because for unknown reasons, hidden
87 * windows get shown when clicking the dock icon when the application
88 * is not already active.
94 _gdk_quartz_window_did_become_main (window);
97 -(void)windowDidResignMain:(NSNotification *)aNotification
101 window = [[self contentView] gdkWindow];
102 _gdk_quartz_window_did_resign_main (window);
105 /* Used in combination with NSLeftMouseUp in sendEvent to keep track
106 * of when the window is being moved with the mouse.
108 -(void)windowWillMove:(NSNotification *)aNotification
113 -(void)sendEvent:(NSEvent *)event
115 switch ([event type])
123 case NSLeftMouseDragged:
124 if ([self trackManualMove] || [self trackManualResize])
132 [super sendEvent:event];
140 -(void)windowDidMove:(NSNotification *)aNotification
142 NSRect content_rect = [self contentRectForFrameRect:[self frame]];
143 GdkWindow *window = [[self contentView] gdkWindow];
144 GdkWindowObject *private = (GdkWindowObject *)window;
147 private->x = content_rect.origin.x;
148 private->y = _gdk_quartz_window_get_inverted_screen_y (content_rect.origin.y + content_rect.size.height);
150 /* Synthesize a configure event */
151 event = gdk_event_new (GDK_CONFIGURE);
152 event->configure.window = g_object_ref (window);
153 event->configure.x = private->x;
154 event->configure.y = private->y;
155 event->configure.width = private->width;
156 event->configure.height = private->height;
158 _gdk_event_queue_append (gdk_display_get_default (), event);
161 -(void)windowDidResize:(NSNotification *)aNotification
163 NSRect content_rect = [self contentRectForFrameRect:[self frame]];
164 GdkWindow *window = [[self contentView] gdkWindow];
165 GdkWindowObject *private = (GdkWindowObject *)window;
168 private->width = content_rect.size.width;
169 private->height = content_rect.size.height;
171 [[self contentView] setFrame:NSMakeRect (0, 0, private->width, private->height)];
173 /* Synthesize a configure event */
174 event = gdk_event_new (GDK_CONFIGURE);
175 event->configure.window = g_object_ref (window);
176 event->configure.x = private->x;
177 event->configure.y = private->y;
178 event->configure.width = private->width;
179 event->configure.height = private->height;
181 _gdk_event_queue_append (gdk_display_get_default (), event);
184 -(id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
186 self = [super initWithContentRect:contentRect
191 [self setAcceptsMouseMovedEvents:YES];
192 [self setDelegate:self];
193 [self setReleasedWhenClosed:YES];
198 -(BOOL)canBecomeMainWindow
200 GdkWindow *window = [[self contentView] gdkWindow];
201 GdkWindowObject *private = (GdkWindowObject *)window;
202 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
204 switch (impl->type_hint)
206 case GDK_WINDOW_TYPE_HINT_NORMAL:
207 case GDK_WINDOW_TYPE_HINT_DIALOG:
210 case GDK_WINDOW_TYPE_HINT_MENU:
211 case GDK_WINDOW_TYPE_HINT_TOOLBAR:
212 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
213 case GDK_WINDOW_TYPE_HINT_UTILITY:
214 case GDK_WINDOW_TYPE_HINT_DOCK:
215 case GDK_WINDOW_TYPE_HINT_DESKTOP:
216 case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
217 case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
218 case GDK_WINDOW_TYPE_HINT_TOOLTIP:
219 case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
220 case GDK_WINDOW_TYPE_HINT_COMBO:
221 case GDK_WINDOW_TYPE_HINT_DND:
228 -(BOOL)canBecomeKeyWindow
230 GdkWindow *window = [[self contentView] gdkWindow];
231 GdkWindowObject *private = (GdkWindowObject *)window;
232 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
234 if (!private->accept_focus)
237 /* Popup windows should not be able to get focused in the window
238 * manager sense, it's only handled through grabs.
240 if (private->window_type == GDK_WINDOW_TEMP)
243 switch (impl->type_hint)
245 case GDK_WINDOW_TYPE_HINT_NORMAL:
246 case GDK_WINDOW_TYPE_HINT_DIALOG:
247 case GDK_WINDOW_TYPE_HINT_MENU:
248 case GDK_WINDOW_TYPE_HINT_TOOLBAR:
249 case GDK_WINDOW_TYPE_HINT_UTILITY:
250 case GDK_WINDOW_TYPE_HINT_DOCK:
251 case GDK_WINDOW_TYPE_HINT_DESKTOP:
252 case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
253 case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
254 case GDK_WINDOW_TYPE_HINT_COMBO:
257 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
258 case GDK_WINDOW_TYPE_HINT_TOOLTIP:
259 case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
260 case GDK_WINDOW_TYPE_HINT_DND:
267 - (void)showAndMakeKey:(BOOL)makeKey
269 GdkWindow *window = [[self contentView] gdkWindow];
270 GdkWindowObject *private = (GdkWindowObject *)window;
271 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
276 [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
278 [impl->toplevel orderFront:nil];
285 GdkWindow *window = [[self contentView] gdkWindow];
286 GdkWindowObject *private = (GdkWindowObject *)window;
287 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
290 [impl->toplevel orderOut:nil];
294 - (BOOL)trackManualMove
296 NSPoint currentLocation;
298 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
299 NSRect windowFrame = [self frame];
304 currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
305 newOrigin.x = currentLocation.x - initialMoveLocation.x;
306 newOrigin.y = currentLocation.y - initialMoveLocation.y;
308 /* Clamp vertical position to below the menu bar. */
309 if (newOrigin.y + windowFrame.size.height > screenFrame.origin.y + screenFrame.size.height)
310 newOrigin.y = screenFrame.origin.y + screenFrame.size.height - windowFrame.size.height;
312 [self setFrameOrigin:newOrigin];
317 -(void)beginManualMove
319 NSRect frame = [self frame];
321 if (inMove || inManualMove || inManualResize)
326 initialMoveLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
327 initialMoveLocation.x -= frame.origin.x;
328 initialMoveLocation.y -= frame.origin.y;
331 - (BOOL)trackManualResize
333 NSPoint currentLocation;
338 if (!inManualResize || inTrackManualResize)
341 inTrackManualResize = YES;
343 currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
344 currentLocation.x -= initialResizeFrame.origin.x;
345 currentLocation.y -= initialResizeFrame.origin.y;
347 dx = currentLocation.x - initialResizeLocation.x;
348 dy = -(currentLocation.y - initialResizeLocation.y);
350 newFrame = initialResizeFrame;
351 newFrame.size.width = initialResizeFrame.size.width + dx;
352 newFrame.size.height = initialResizeFrame.size.height + dy;
354 min_size = [self contentMinSize];
355 if (newFrame.size.width < min_size.width)
356 newFrame.size.width = min_size.width;
357 if (newFrame.size.height < min_size.height)
358 newFrame.size.height = min_size.height;
360 /* We could also apply aspect ratio:
361 newFrame.size.height = newFrame.size.width / [self aspectRatio].width * [self aspectRatio].height;
364 dy = newFrame.size.height - initialResizeFrame.size.height;
366 newFrame.origin.x = initialResizeFrame.origin.x;
367 newFrame.origin.y = initialResizeFrame.origin.y - dy;
369 [self setFrame:newFrame display:YES];
371 /* Let the resizing be handled by GTK+. */
372 if (g_main_context_pending (NULL))
373 g_main_context_iteration (NULL, FALSE);
375 inTrackManualResize = NO;
380 -(void)beginManualResize
382 if (inMove || inManualMove || inManualResize)
385 inManualResize = YES;
387 initialResizeFrame = [self frame];
388 initialResizeLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
389 initialResizeLocation.x -= initialResizeFrame.origin.x;
390 initialResizeLocation.y -= initialResizeFrame.origin.y;
395 static GdkDragContext *current_context = NULL;
398 drag_operation_to_drag_action (NSDragOperation operation)
400 GdkDragAction result = 0;
402 if (operation & NSDragOperationGeneric)
403 result |= GDK_ACTION_COPY;
408 static NSDragOperation
409 drag_action_to_drag_operation (GdkDragAction action)
411 NSDragOperation result = 0;
413 if (action & GDK_ACTION_COPY)
414 result |= NSDragOperationCopy;
420 update_context_from_dragging_info (id <NSDraggingInfo> sender)
422 g_assert (current_context != NULL);
424 GDK_DRAG_CONTEXT_PRIVATE (current_context)->dragging_info = sender;
425 current_context->suggested_action = drag_operation_to_drag_action ([sender draggingSourceOperationMask]);
428 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
433 g_object_unref (current_context);
435 current_context = gdk_drag_context_new ();
436 update_context_from_dragging_info (sender);
438 event.dnd.type = GDK_DRAG_ENTER;
439 event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
440 event.dnd.send_event = FALSE;
441 event.dnd.context = current_context;
442 event.dnd.time = GDK_CURRENT_TIME;
444 (*_gdk_event_func) (&event, _gdk_event_data);
446 return NSDragOperationNone;
449 - (void)draggingEnded:(id <NSDraggingInfo>)sender
452 g_object_unref (current_context);
453 current_context = NULL;
456 - (void)draggingExited:(id <NSDraggingInfo>)sender
460 event.dnd.type = GDK_DRAG_LEAVE;
461 event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
462 event.dnd.send_event = FALSE;
463 event.dnd.context = current_context;
464 event.dnd.time = GDK_CURRENT_TIME;
466 (*_gdk_event_func) (&event, _gdk_event_data);
468 g_object_unref (current_context);
469 current_context = NULL;
472 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
474 NSPoint point = [sender draggingLocation];
475 NSPoint screen_point = [self convertBaseToScreen:point];
478 update_context_from_dragging_info (sender);
480 event.dnd.type = GDK_DRAG_MOTION;
481 event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
482 event.dnd.send_event = FALSE;
483 event.dnd.context = current_context;
484 event.dnd.time = GDK_CURRENT_TIME;
485 event.dnd.x_root = screen_point.x;
486 event.dnd.y_root = _gdk_quartz_window_get_inverted_screen_y (screen_point.y);
488 (*_gdk_event_func) (&event, _gdk_event_data);
490 g_object_unref (event.dnd.window);
492 return drag_action_to_drag_operation (current_context->action);
495 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
497 NSPoint point = [sender draggingLocation];
498 NSPoint screen_point = [self convertBaseToScreen:point];
501 update_context_from_dragging_info (sender);
503 event.dnd.type = GDK_DROP_START;
504 event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
505 event.dnd.send_event = FALSE;
506 event.dnd.context = current_context;
507 event.dnd.time = GDK_CURRENT_TIME;
508 event.dnd.x_root = screen_point.x;
509 event.dnd.y_root = _gdk_quartz_window_get_inverted_screen_y (screen_point.y);
511 (*_gdk_event_func) (&event, _gdk_event_data);
513 g_object_unref (event.dnd.window);
515 g_object_unref (current_context);
516 current_context = NULL;
521 - (BOOL)wantsPeriodicDraggingUpdates
526 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
530 g_assert (_gdk_quartz_drag_source_context != NULL);
532 event.dnd.type = GDK_DROP_FINISHED;
533 event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
534 event.dnd.send_event = FALSE;
535 event.dnd.context = _gdk_quartz_drag_source_context;
537 (*_gdk_event_func) (&event, _gdk_event_data);
539 g_object_unref (event.dnd.window);
541 g_object_unref (_gdk_quartz_drag_source_context);
542 _gdk_quartz_drag_source_context = NULL;