Skip to content

Commit

Permalink
First shot at SDL_SetWindowDragAreas().
Browse files Browse the repository at this point in the history
Only Cocoa implemented right now.
  • Loading branch information
icculus committed May 27, 2014
1 parent b7f9044 commit 3cbc83e
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 2 deletions.
1 change: 1 addition & 0 deletions .hgignore
Expand Up @@ -55,6 +55,7 @@ test/loopwave
test/testatomic
test/testaudioinfo
test/testautomation
test/testdragareas
test/testdraw2
test/testerror
test/testfile
Expand Down
38 changes: 38 additions & 0 deletions include/SDL_video.h
Expand Up @@ -791,6 +791,44 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window,
Uint16 * green,
Uint16 * blue);

/**
* \brief Define regions of a window that can be used to drag it.
*
* Normally windows are dragged by decorations provided by the system
* window manager (usually, a title bar), but for some apps, it makes sense
* to drag them from somewhere else inside the window itself; for example,
* one might have a borderless window that wants to be draggable from any
* part, or simulate its own title bar, etc.
*
* This method designates pieces of a given window as "drag areas," which
* will move the window when the user drags with his mouse, as if she had
* used the titlebar.
*
* You may specify multiple drag areas, disconnected or overlapping. This
* function accepts an array of rectangles. Each call to this function will
* replace any previously-defined drag areas. To disable drag areas on a
* window, call this function with a NULL array of zero elements.
*
* Drag areas do not automatically resize. If your window changes dimensions
* you should plan to re-call this function with new drag areas if
* appropriate.
*
* Mouse input may not be delivered to your application if it is within
* a drag area; the OS will often apply that input to moving the window and
* not deliver it to the application.
*
* Platforms that don't support this functionality will return -1
* unconditionally, even if you're attempting to disable drag areas.
*
* \param window The window to set drag areas on.
* \param areas An array of SDL_Rects containing num_areas elements.
* \param num_areas The number of elements in the areas parameter.
* \return 0 on success, -1 on error (including unsupported).
*/
extern DECLSPEC int SDLCALL SDL_SetWindowDragAreas(SDL_Window * window,
const SDL_Rect *areas,
int num_areas);

/**
* \brief Destroy a window.
*/
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Expand Up @@ -580,3 +580,4 @@
#define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL
#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
#define SDL_CaptureMouse SDL_CaptureMouse_REAL
#define SDL_SetWindowDragAreas SDL_SetWindowDragAreas_REAL
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_procs.h
Expand Up @@ -613,3 +613,4 @@ SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return
SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
#endif
SDL_DYNAPI_PROC(int,SDL_CaptureMouse,(SDL_bool a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowDragAreas,(SDL_Window *a, const SDL_Rect *b, int c),(a,b,c),return)
6 changes: 6 additions & 0 deletions src/video/SDL_sysvideo.h
Expand Up @@ -97,6 +97,9 @@ struct SDL_Window

SDL_WindowShaper *shaper;

int num_drag_areas;
SDL_Rect *drag_areas;

SDL_WindowUserData *data;

void *driverdata;
Expand Down Expand Up @@ -261,6 +264,9 @@ struct SDL_VideoDevice
/* MessageBox */
int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);

/* Drag areas. Note that (areas) and (num_areas) are also copied to the SDL_Window for you after this call. */
int (*SetWindowDragAreas)(SDL_Window * window, const SDL_Rect *areas, int num_areas);

/* * * */
/* Data common to all drivers */
SDL_bool suspend_screensaver;
Expand Down
37 changes: 37 additions & 0 deletions src/video/SDL_video.c
Expand Up @@ -1410,6 +1410,11 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
SDL_SetWindowIcon(window, icon);
SDL_FreeSurface(icon);
}

if (window->num_drag_areas > 0) {
_this->SetWindowDragAreas(window, window->drag_areas, window->num_drag_areas);
}

SDL_FinishWindowCreation(window, flags);

return 0;
Expand Down Expand Up @@ -2305,6 +2310,8 @@ SDL_DestroyWindow(SDL_Window * window)
_this->windows = window->next;
}

SDL_free(window->drag_areas);

SDL_free(window);
}

Expand Down Expand Up @@ -3380,4 +3387,34 @@ SDL_ShouldAllowTopmost(void)
return SDL_TRUE;
}

int
SDL_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *_areas, int num_areas)
{
SDL_Rect *areas = NULL;

CHECK_WINDOW_MAGIC(window, -1);

if (!_this->SetWindowDragAreas) {
return SDL_Unsupported();
}

if (num_areas > 0) {
const size_t len = sizeof (SDL_Rect) * num_areas;
areas = (SDL_Rect *) SDL_malloc(len);
if (!areas) {
return SDL_OutOfMemory();
}
SDL_memcpy(areas, _areas, len);
}

if (_this->SetWindowDragAreas(window, areas, num_areas) == -1) {
SDL_free(areas);
return -1;
}

SDL_free(window->drag_areas);
window->drag_areas = areas;
window->num_drag_areas = num_areas;
}

/* vi: set ts=4 sw=4 expandtab: */
1 change: 1 addition & 0 deletions src/video/cocoa/SDL_cocoavideo.m
Expand Up @@ -108,6 +108,7 @@
device->SetWindowGrab = Cocoa_SetWindowGrab;
device->DestroyWindow = Cocoa_DestroyWindow;
device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
device->SetWindowDragAreas = Cocoa_SetWindowDragAreas;

device->shape_driver.CreateShaper = Cocoa_CreateShaper;
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
Expand Down
9 changes: 7 additions & 2 deletions src/video/cocoa/SDL_cocoawindow.h
Expand Up @@ -45,6 +45,7 @@ typedef enum
PendingWindowOperation pendingWindowOperation;
BOOL isMoving;
int pendingWindowWarpX, pendingWindowWarpY;
BOOL isDragAreaRunning;
}

-(void) listen:(SDL_WindowData *) data;
Expand Down Expand Up @@ -75,6 +76,9 @@ typedef enum
-(void) windowDidExitFullScreen:(NSNotification *) aNotification;
-(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;

/* See if event is in a drag area, toggle on window dragging. */
-(BOOL) processDragArea:(NSEvent *)theEvent;

/* Window event handling */
-(void) mouseDown:(NSEvent *) theEvent;
-(void) rightMouseDown:(NSEvent *) theEvent;
Expand Down Expand Up @@ -115,6 +119,7 @@ struct SDL_WindowData
SDL_bool inWindowMove;
Cocoa_WindowListener *listener;
struct SDL_VideoData *videodata;
NSView *dragarea;
};

extern int Cocoa_CreateWindow(_THIS, SDL_Window * window);
Expand All @@ -138,8 +143,8 @@ extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * r
extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window);
extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info);
extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info);
extern int Cocoa_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas);

#endif /* _SDL_cocoawindow_h */

Expand Down
60 changes: 60 additions & 0 deletions src/video/cocoa/SDL_cocoawindow.m
Expand Up @@ -180,6 +180,7 @@ - (void)listen:(SDL_WindowData *)data
inFullscreenTransition = NO;
pendingWindowOperation = PENDING_OPERATION_NONE;
isMoving = NO;
isDragAreaRunning = NO;

center = [NSNotificationCenter defaultCenter];

Expand Down Expand Up @@ -656,10 +657,46 @@ - (void)doCommandBySelector:(SEL)aSelector
/*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
}

- (BOOL)processDragArea:(NSEvent *)theEvent
{
const int num_areas = _data->window->num_drag_areas;

SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
SDL_assert((num_areas > 0) || !isDragAreaRunning);

if (num_areas > 0) { /* if no drag areas, skip this. */
int i;
const NSPoint location = [theEvent locationInWindow];
const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
const SDL_Rect *areas = _data->window->drag_areas;
for (i = 0; i < num_areas; i++) {
if (SDL_PointInRect(&point, &areas[i])) {
if (!isDragAreaRunning) {
isDragAreaRunning = YES;
[_data->nswindow setMovableByWindowBackground:YES];
}
return YES; /* started a new drag! */
}
}
}

if (isDragAreaRunning) {
isDragAreaRunning = NO;
[_data->nswindow setMovableByWindowBackground:NO];
return YES; /* was dragging, drop event. */
}

return NO; /* not a drag area, carry on. */
}

- (void)mouseDown:(NSEvent *)theEvent
{
int button;

if ([self processDragArea:theEvent]) {
return; /* dragging, drop event. */
}

switch ([theEvent buttonNumber]) {
case 0:
if (([theEvent modifierFlags] & NSControlKeyMask) &&
Expand Down Expand Up @@ -698,6 +735,10 @@ - (void)mouseUp:(NSEvent *)theEvent
{
int button;

if ([self processDragArea:theEvent]) {
return; /* stopped dragging, drop event. */
}

switch ([theEvent buttonNumber]) {
case 0:
if (wasCtrlLeft) {
Expand Down Expand Up @@ -737,6 +778,10 @@ - (void)mouseMoved:(NSEvent *)theEvent
NSPoint point;
int x, y;

if ([self processDragArea:theEvent]) {
return; /* dragging, drop event. */
}

if (mouse->relative_mode) {
return;
}
Expand Down Expand Up @@ -883,6 +928,7 @@ @interface SDLView : NSView

/* The default implementation doesn't pass rightMouseDown to responder chain */
- (void)rightMouseDown:(NSEvent *)theEvent;
- (BOOL)mouseDownCanMoveWindow;
@end

@implementation SDLView
Expand All @@ -891,6 +937,14 @@ - (void)rightMouseDown:(NSEvent *)theEvent
[[self nextResponder] rightMouseDown:theEvent];
}

- (BOOL)mouseDownCanMoveWindow
{
/* Always say YES, but this doesn't do anything until we call
-[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
during mouse events when we're using a drag area. */
return YES;
}

- (void)resetCursorRects
{
[super resetCursorRects];
Expand Down Expand Up @@ -1544,6 +1598,12 @@ - (void)resetCursorRects
return succeeded;
}

int
Cocoa_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *areas, int num_areas)
{
return 0; /* just succeed, the real work is done elsewhere. */
}

#endif /* SDL_VIDEO_DRIVER_COCOA */

/* vi: set ts=4 sw=4 expandtab: */
4 changes: 4 additions & 0 deletions test/Makefile.in
Expand Up @@ -12,6 +12,7 @@ TARGETS = \
loopwave$(EXE) \
testaudioinfo$(EXE) \
testautomation$(EXE) \
testdragareas$(EXE) \
testdraw2$(EXE) \
testdrawchessboard$(EXE) \
testdropfile$(EXE) \
Expand Down Expand Up @@ -108,6 +109,9 @@ testintersections$(EXE): $(srcdir)/testintersections.c
testrelative$(EXE): $(srcdir)/testrelative.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

testdragareas$(EXE): $(srcdir)/testdragareas.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

testdraw2$(EXE): $(srcdir)/testdraw2.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

Expand Down

0 comments on commit 3cbc83e

Please sign in to comment.