API  1.0.0
CPDragServer.j
Go to the documentation of this file.
1 /*
2  * CPDragServer.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 @global CPApp
26 
27 #define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
28 
31 
33 
36 
37 /*
38  CPDraggingInfo is a container of information about a specific dragging session.
39  @ignore
40 */
41 @implementation CPDraggingInfo : CPObject
42 {
43  id __doxygen__;
44 }
45 
46 - (CPPasteboard)draggingPasteboard
47 {
48  if ([CPPlatform supportsDragAndDrop])
49  return [_CPDOMDataTransferPasteboard DOMDataTransferPasteboard];
50 
52 }
53 
54 - (id)draggingSource
55 {
57 }
58 
59 /*
60 - (unsigned)draggingSourceOperationMask
61 */
62 
63 - (CGPoint)draggingLocation
64 {
66 }
67 
68 - (CPWindow)draggingDestinationWindow
69 {
70  return DRAGGING_WINDOW([[CPDragServer sharedDragServer] draggingDestination]);
71 }
72 
73 - (CPImage)draggedImage
74 {
75  return [[self draggedView] image];
76 }
77 
78 - (CGPoint)draggedImageLocation
79 {
80  return [self draggedViewLocation];
81 }
82 
83 - (CPView)draggedView
84 {
86 }
87 
88 - (CGPoint)draggedViewLocation
89 {
90  var dragServer = [CPDragServer sharedDragServer];
91 
92  return [DRAGGING_WINDOW([dragServer draggingDestination]) convertPlatformWindowToBase:[[dragServer draggedView] frame].origin];
93 }
94 
95 @end
96 
101 
102 @implementation CPDragServer : CPObject
103 {
104  BOOL _isDragging;
105 
106  CPWindow _draggedWindow;
107  CPView _draggedView;
108  CPImageView _imageView;
109 
110  BOOL _isDraggingImage;
111 
112  CGSize _draggingOffset;
113 
114  CPPasteboard _draggingPasteboard;
115 
116  id _draggingSource;
117  unsigned _implementedDraggingSourceMethods;
118 
119  CGPoint _draggingLocation;
120  id _draggingDestination;
121  BOOL _draggingDestinationWantsPeriodicUpdates;
122 
123  CGPoint _startDragLocation;
124  BOOL _shouldSlideBack;
125  unsigned _dragOperation;
126 
127  CPTimer _draggingUpdateTimer;
128 }
129 
130 /*
131  Private Objective-J/Cappuccino method
132  @ignore
133 */
134 + (void)initialize
135 {
136  if (self !== [CPDragServer class])
137  return;
138 
140 }
141 
142 + (CPDragServer)sharedDragServer
143 {
144  if (!CPSharedDragServer)
146 
147  return CPSharedDragServer;
148 }
149 
150 /*
151  @ignore
152 */
153 - (id)init
154 {
155  self = [super init];
156 
157  if (self)
158  {
159  _draggedWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessWindowMask];
160 
161  [_draggedWindow setLevel:CPDraggingWindowLevel];
162  }
163 
164  return self;
165 }
166 
167 - (id)draggingDestination
168 {
169  return _draggingDestination;
170 }
171 
172 - (CGPoint)draggingLocation
173 {
174  return _draggingLocation
175 }
176 
177 - (void)draggingStartedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
178 {
179  if (_isDraggingImage)
180  {
181  if ([_draggingSource respondsToSelector:@selector(draggedImage:beganAt:)])
182  [_draggingSource draggedImage:[_draggedView image] beganAt:aLocation];
183  }
184  else
185  {
186  if ([_draggingSource respondsToSelector:@selector(draggedView:beganAt:)])
187  [_draggingSource draggedView:_draggedView beganAt:aLocation];
188  }
189 
190  if (![CPPlatform supportsDragAndDrop])
191  [_draggedWindow orderFront:self];
192 }
193 
194 - (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
195 {
196  if (![CPPlatform supportsDragAndDrop])
197  {
198  var frame = [_draggedWindow frame];
199  frame.origin.x = aGlobalLocation.x - _draggingOffset.width;
200  frame.origin.y = aGlobalLocation.y - _draggingOffset.height;
201  [_draggedWindow _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
202  }
203 
204  if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_movedTo_)
205  [_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
206 
207  else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_movedTo_)
208  [_draggingSource draggedView:_draggedView movedTo:aGlobalLocation];
209 }
210 
211 - (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
212 {
213  [_draggingUpdateTimer invalidate];
214  _draggingUpdateTimer = nil;
215 
216  var dragOperation = CPDragOperationCopy,
217  // We have to convert base to bridge since the drag event comes from the source window, not the drag window.
218  draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
219 
220  if (draggingDestination)
221  _draggingLocation = [DRAGGING_WINDOW(draggingDestination) convertPlatformWindowToBase:aLocation];
222 
223  if (draggingDestination !== _draggingDestination)
224  {
225  if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
226  [_draggingDestination draggingExited:CPDragServerDraggingInfo];
227 
228  _draggingDestination = draggingDestination;
229 
230  if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)])
231  _draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
232  else
233  _draggingDestinationWantsPeriodicUpdates = YES;
234 
235  if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
236  dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
237  }
238  else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
239  dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
240 
241  if (!_draggingDestination)
242  dragOperation = CPDragOperationNone;
243  else
244  {
245  if (_draggingDestinationWantsPeriodicUpdates)
246  _draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
247  target:self
249  userInfo:@{ "platformWindow":aPlatformWindow, "location":aLocation }
250  repeats:NO];
251 
252  var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
253  if (scrollView)
254  {
255  var contentView = [scrollView contentView],
256  bounds = [contentView bounds],
257  insetBounds = CGRectInset(bounds, 30, 30),
258  eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
259  deltaX = 0,
260  deltaY = 0;
261 
262  if (!CGRectContainsPoint(insetBounds, eventLocation))
263  {
264  if ([scrollView hasVerticalScroller])
265  {
266  if (eventLocation.y < CGRectGetMinY(insetBounds))
267  deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
268  else if (eventLocation.y > CGRectGetMaxY(insetBounds))
269  deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
270  if (deltaY < -insetBounds.size.height)
271  deltaY = -insetBounds.size.height;
272  if (deltaY > insetBounds.size.height)
273  deltaY = insetBounds.size.height;
274  }
275 
276  if ([scrollView hasHorizontalScroller])
277  {
278  if (eventLocation.x < CGRectGetMinX(insetBounds))
279  deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
280  else if (eventLocation.x > CGRectGetMaxX(insetBounds))
281  deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
282  if (deltaX < -insetBounds.size.width)
283  deltaX = -insetBounds.size.width;
284  if (deltaX > insetBounds.size.width)
285  deltaX = insetBounds.size.width;
286  }
287 
288  var scrollPoint = CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
289 
290  [contentView scrollToPoint:scrollPoint];
291  [[scrollView _headerView] scrollPoint:scrollPoint];
292 
293  }
294  }
295  }
296 
297  return dragOperation;
298 }
299 
300 - (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
301 {
302  var userInfo = [aTimer userInfo];
303  _dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
304  location:[userInfo objectForKey:@"location"]];
305 }
306 
307 - (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
308 {
309  [_draggingUpdateTimer invalidate];
310  _draggingUpdateTimer = nil;
311 
312  [_draggedView removeFromSuperview];
313 
314  if (![CPPlatform supportsDragAndDrop])
315  [_draggedWindow orderOut:self];
316 
317  if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
318  [_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
319  else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
320  [_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
321 
322  _isDragging = NO;
323 }
324 
325 - (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
326 {
327  if (_draggingDestination &&
328  (![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
329  (![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
330  [_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
331  [_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
332 }
333 
346 - (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)mouseDownEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
347 {
348  _isDragging = YES;
349 
350  _draggedView = aView;
351  _draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
352  _draggingSource = aSourceObject;
353  _draggingDestination = nil;
354  _shouldSlideBack = slideBack;
355 
356  // The offset is based on the distance from where we want the view to be initially from where the mouse is initially
357  // Hence the use of mouseDownEvent's location and view's location in global coordinates.
358  var mouseDownWindow = [mouseDownEvent window],
359  mouseDownEventLocation = [mouseDownEvent locationInWindow];
360 
361  if (mouseDownEventLocation)
362  {
363  if (mouseDownWindow)
364  mouseDownEventLocation = [mouseDownWindow convertBaseToGlobal:mouseDownEventLocation];
365 
366  _draggingOffset = CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
367  }
368  else
369  _draggingOffset = CGSizeMakeZero();
370 
371  if ([CPPlatform isBrowser])
372  [_draggedWindow setPlatformWindow:[aWindow platformWindow]];
373 
374  [aView setFrameOrigin:CGPointMakeZero()];
375 
376  var mouseLocation = [CPEvent mouseLocation],
377  viewSize = [aView frameSize],
378  startDragLocationX = mouseLocation.x - _draggingOffset.width,
379  startDragLocationY = mouseLocation.y - _draggingOffset.height,
380  draggedWindowFrame = CGRectMake(startDragLocationX, startDragLocationY, viewSize.width, viewSize.height);
381 
382  // Place it where the mouse pointer is.
383  _startDragLocation = CGPointMake(startDragLocationX, startDragLocationY);
384 
385  [_draggedWindow _setFrame:draggedWindowFrame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
386 
387  [[_draggedWindow contentView] addSubview:aView];
388 
389  _implementedDraggingSourceMethods = 0;
390 
391  if (_draggedView === _imageView)
392  {
393  if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
394  _implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
395 
396  if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
397  _implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
398  }
399  else
400  {
401  if ([_draggingSource respondsToSelector:@selector(draggedView:movedTo:)])
402  _implementedDraggingSourceMethods |= CPDraggingSource_draggedView_movedTo_;
403 
404  if ([_draggingSource respondsToSelector:@selector(draggedView:endedAt:operation:)])
405  _implementedDraggingSourceMethods |= CPDraggingSource_draggedView_endedAt_operation_;
406  }
407 
408  if (![CPPlatform supportsDragAndDrop])
409  {
410  [self draggingStartedInPlatformWindow:[aWindow platformWindow] globalLocation:mouseLocation];
411  [self trackDragging:mouseDownEvent];
412  }
413 }
414 
427 - (void)dragImage:(CPImage)anImage fromWindow:(CPWindow)aWindow at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
428 {
429  _isDraggingImage = YES;
430 
431  var imageSize = [anImage size];
432 
433  if (!_imageView)
434  _imageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, imageSize.width, imageSize.height)];
435 
436  [_imageView setImage:anImage];
437 
438  [self dragView:_imageView fromWindow:aWindow at:imageLocation offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
439 }
440 
441 - (void)trackDragging:(CPEvent)anEvent
442 {
443  var type = [anEvent type],
444  platformWindow = [_draggedWindow platformWindow],
445  platformWindowLocation = [[anEvent window] convertBaseToPlatformWindow:[anEvent locationInWindow]];
446 
447  if (type === CPLeftMouseUp)
448  {
449  // Make sure we do not finalize (cancel) the drag if the last drag update was disallowed
450  if (_dragOperation !== CPDragOperationNone)
451  [self performDragOperationInPlatformWindow:platformWindow];
452 
453  [self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:_dragOperation];
454 
455  // Stop tracking events.
456  return;
457  }
458  else if (type === CPKeyDown)
459  {
460  var characters = [anEvent characters];
461 
462  if (characters === CPEscapeFunctionKey)
463  {
464  _dragOperation = CPDragOperationNone;
465  [self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
466  return;
467  }
468  }
469  else
470  {
471  [self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
472  _dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
473  }
474 
475  // If we're not a mouse up, then we're going to want to grab the next event.
476  [CPApp setTarget:self selector:@selector(trackDragging:)
477  forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
478  untilDate:nil inMode:0 dequeue:YES];
479 }
480 
481 @end
482 
484 
488 - (BOOL)isDragging
489 {
490  return _isDragging;
491 }
492 
496 - (CPWindow)draggedWindow
497 {
498  return _draggedWindow;
499 }
500 
504 - (CPView)draggedView
505 {
506  return _draggedView;
507 }
508 
512 - (CGSize)draggingOffset
513 {
514  return _draggingOffset;
515 }
516 
520 - (CPPasteboard)draggingPasteboard
521 {
522  return _draggingPasteboard;
523 }
524 
528 - (id)draggingSource
529 {
530  return _draggingSource;
531 }
532 
533 @end
CGPoint draggingLocation()
Definition: CPDragServer.j:172
CGPoint convertBaseToPlatformWindow:(CGPoint aPoint)
Definition: CPWindow.j:3633
id init()
Definition: CALayer.j:126
CPPasteboard draggingPasteboard()
Definition: CPDragServer.j:520
CGRect frame
CPDragOperation CPDragOperationNone
CGSize size()
Definition: CPImage.j:267
var CPDragServerDraggingInfo
Definition: CPDragServer.j:35
CGPoint locationInWindow()
Definition: CPEvent.j:290
void trackDragging:(CPEvent anEvent)
Definition: CPDragServer.j:441
CPEventType type()
Definition: CPEvent.j:325
CGPoint draggedViewLocation()
Definition: CPDragServer.j:88
void draggingStartedInPlatformWindow:globalLocation:(CPPlatformWindow aPlatformWindow, [globalLocation] CGPoint aLocation)
Definition: CPDragServer.j:177
CPView draggedView()
Definition: CPDragServer.j:504
#define DRAGGING_WINDOW(anObject)
Definition: CPDragServer.j:27
var CPDragServerPreviousEvent
Definition: CPDragServer.j:29
CGRect bounds()
Definition: CALayer.j:203
CGSize frameSize()
Definition: CPView.j:1056
id initWithContentRect:styleMask:(CGRect aContentRect, [styleMask] unsigned aStyleMask)
Definition: CPWindow.j:265
CGPoint mouseLocation()
Definition: CPEvent.j:417
void draggingSourceUpdatedWithGlobalLocation:(CGPoint aGlobalLocation)
Definition: CPDragServer.j:194
var CPDragServerPeriodicUpdateInterval
Definition: CPDragServer.j:30
Definition: CPImage.h:2
CPEscapeFunctionKey
CPKeyDown
CPDragServer sharedDragServer()
Definition: CPDragServer.j:142
var CPDraggingSource_draggedImage_movedTo_
Definition: CPDragServer.j:97
CPWindow window()
Definition: CPEvent.j:341
CPLeftMouseUp
void dragView:fromWindow:at:offset:event:pasteboard:source:slideBack:(CPView aView, [fromWindow] CPWindow aWindow, [at] CGPoint viewLocation, [offset] CGSize mouseOffset, [event] CPEvent mouseDownEvent, [pasteboard] CPPasteboard aPasteboard, [source] id aSourceObject, [slideBack] BOOL slideBack)
Definition: CPDragServer.j:346
CPTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:(CPTimeInterval seconds, [target] id aTarget, [selector] SEL aSelector, [userInfo] id userInfo, [repeats] BOOL shouldRepeat)
Definition: CPTimer.j:58
void performDragOperationInPlatformWindow:(CPPlatformWindow aPlatformWindow)
Definition: CPDragServer.j:325
var CPDragServerSource
Definition: CPDragServer.j:34
var CPDraggingSource_draggedView_endedAt_operation_
Definition: CPDragServer.j:100
id userInfo()
Definition: CPTimer.j:229
A timer object that can send a message after the given time interval.
Definition: CPTimer.h:2
CPView draggedView()
Definition: CPDragServer.j:83
var CPDraggingSource_draggedView_movedTo_
Definition: CPDragServer.j:99
var CPDraggingSource_draggedImage_endedAt_operation_
Definition: CPDragServer.j:98
id init()
Definition: CPObject.j:145
void draggingEndedInPlatformWindow:globalLocation:operation:(CPPlatformWindow aPlatformWindow, [globalLocation] CGPoint aLocation, [operation] CPDragOperation anOperation)
Definition: CPDragServer.j:307
var CPSharedDragServer
Definition: CPDragServer.j:32
Definition: CPEvent.h:2
CPPlatformWindow platformWindow()
Definition: CPWindow.j:389
CPDragOperation draggingUpdatedInPlatformWindow:location:(CPPlatformWindow aPlatformWindow, [location] CGPoint aLocation)
Definition: CPDragServer.j:211
CPDragOperationCopy
void setFrameOrigin:(CGPoint aPoint)
Definition: CPView.j:1089
id pasteboardWithName:(CPString aName)
Definition: CPPasteboard.j:93
id alloc()
Definition: CPObject.j:130
CPString characters()
Definition: CPEvent.j:382
Definition: CPView.j:137