SDL-mirror/src/video/bwindow/SDL_BWin.h

601 lines
16 KiB
C
Raw Normal View History

/*
2011-04-08 13:03:26 -07:00
Simple DirectMedia Layer
Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
2011-04-08 13:03:26 -07:00
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
2011-04-08 13:03:26 -07:00
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
2011-04-08 13:03:26 -07:00
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SDL_BWin_h
#define _SDL_BWin_h
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_config.h"
#include "SDL.h"
#include "SDL_syswm.h"
#ifdef __cplusplus
}
#endif
#include <stdio.h>
#include <AppKit.h>
#include <InterfaceKit.h>
#include <be/game/DirectWindow.h>
#if SDL_VIDEO_OPENGL
#include <be/opengl/GLView.h>
#endif
#include "SDL_events.h"
#include "../../main/beos/SDL_BApp.h"
enum WinCommands {
BWIN_MOVE_WINDOW,
BWIN_RESIZE_WINDOW,
BWIN_SHOW_WINDOW,
BWIN_HIDE_WINDOW,
BWIN_MAXIMIZE_WINDOW,
BWIN_MINIMIZE_WINDOW,
BWIN_RESTORE_WINDOW, /* TODO: IMPLEMENT THIS! */
BWIN_SET_TITLE,
BWIN_FULLSCREEN
};
class SDL_BWin:public BDirectWindow
{
public:
/* Constructor/Destructor */
SDL_BWin(BRect bounds):BDirectWindow(bounds, "Untitled",
B_TITLED_WINDOW, 0)
{
2011-07-25 16:46:55 +00:00
_last_buttons = 0;
2011-07-22 16:54:23 +00:00
#if SDL_VIDEO_OPENGL
2011-07-25 16:46:55 +00:00
_SDL_GLView = NULL;
#endif
_shown = false;
2011-07-25 16:46:55 +00:00
_inhibit_resize = false;
_mouse_focused = false;
_prev_frame = NULL;
2011-07-22 12:39:53 +00:00
/* Handle framebuffer stuff */
2011-07-25 16:46:55 +00:00
_connected = _connection_disabled = false;
_trash__window_buffer = false;
_buffer_locker = new BLocker();
_window_buffer = NULL;
2011-07-22 12:39:53 +00:00
// LockBuffer(); /* Unlocked by buffer initialization */
}
virtual ~ SDL_BWin()
{
Lock();
2011-07-25 16:46:55 +00:00
_connection_disabled = true;
2011-07-22 12:39:53 +00:00
#if SDL_VIDEO_OPENGL
2011-07-25 16:46:55 +00:00
if (_SDL_GLView) {
_SDL_GLView->UnlockGL();
}
2011-07-25 16:46:55 +00:00
RemoveChild(_SDL_GLView);
2011-07-22 16:54:23 +00:00
#endif
Unlock();
#if SDL_VIDEO_OPENGL
2011-07-25 16:46:55 +00:00
if (_SDL_GLView) {
delete _SDL_GLView;
}
#endif
2011-07-22 12:39:53 +00:00
/* Clean up framebuffer stuff */
2011-07-25 16:46:55 +00:00
_buffer_locker->Lock();
2011-07-22 16:54:23 +00:00
free(_clips);
2011-07-25 16:46:55 +00:00
delete _buffer_locker;
}
2011-07-22 16:54:23 +00:00
/* Other construction */
2011-07-22 16:54:23 +00:00
#if SDL_VIDEO_OPENGL
virtual int CreateView(Uint32 flags, Uint32 gl_flags)
{
int retval;
retval = 0;
Lock();
if (flags & SDL_OPENGL/*SDL_INTERNALOPENGL*/) {
2011-07-25 16:46:55 +00:00
if (_SDL_GLView == NULL) {
_SDL_GLView = new BGLView(Bounds(), "SDL GLView",
B_FOLLOW_ALL_SIDES,
(B_WILL_DRAW | B_FRAME_EVENTS),
gl_flags);
}
2011-07-25 16:46:55 +00:00
if (_the_view != _SDL_GLView) {
if (_the_view) {
RemoveChild(_the_view);
}
2011-07-25 16:46:55 +00:00
AddChild(_SDL_GLView);
_SDL_GLView->LockGL();
_the_view = _SDL_GLView;
}
} else {
2011-07-25 16:46:55 +00:00
if (_the_view) {
_SDL_GLView->UnlockGL();
RemoveChild(_the_view);
}
}
Unlock();
return (retval);
}
2011-07-22 16:54:23 +00:00
#endif
2011-07-20 19:25:38 +00:00
/* * * * * Framebuffering* * * * */
virtual void DirectConnected(direct_buffer_info *info) {
2011-07-25 16:46:55 +00:00
if(!_connected && _connection_disabled) {
2011-07-22 12:39:53 +00:00
return;
}
LockBuffer();
switch(info->buffer_state & B_DIRECT_MODE_MASK) {
case B_DIRECT_START:
_connected = true;
case B_DIRECT_MODIFY:
if(_clips) {
free(_clips);
_clips = NULL;
}
2011-07-22 16:54:23 +00:00
/* Can we reuse the window's pixel buffer after this? */
2011-07-25 16:46:55 +00:00
_trash__window_buffer = ((info->buffer_state & B_BUFFER_RESIZED)
2011-07-22 16:54:23 +00:00
|| (info->buffer_state & B_BUFFER_RESET)
|| ((info->buffer_state & B_DIRECT_MODE_MASK)
== B_DIRECT_START));
2011-07-25 16:46:55 +00:00
_num_clips = info->clip_list_count;
_clips = (clipping_rect *)malloc(_num_clips*sizeof(clipping_rect));
2011-07-22 12:39:53 +00:00
if(_clips) {
memcpy(_clips, info->clip_list,
2011-07-25 16:46:55 +00:00
_num_clips*sizeof(clipping_rect));
2011-07-22 12:39:53 +00:00
_bits = (uint8*) info->bits;
2011-07-25 16:46:55 +00:00
_row_bytes = info->bytes_per_row;
2011-07-22 12:39:53 +00:00
_bounds = info->window_bounds;
2011-07-25 16:46:55 +00:00
_bytes_per_px = info->bits_per_pixel / 8;
2011-07-22 12:39:53 +00:00
}
2011-07-25 16:46:55 +00:00
/* Whatever the case, I think this merits a repaint event */
// _RepaintEvent();
2011-07-22 12:39:53 +00:00
break;
case B_DIRECT_STOP:
_connected = false;
break;
}
UnlockBuffer();
2011-07-20 19:25:38 +00:00
}
2011-07-22 16:54:23 +00:00
/* * * * * Event sending * * * * */
/* Hook functions */
virtual void FrameMoved(BPoint origin) {
/* Post a message to the BApp so that it can handle the window event */
BMessage msg(BAPP_WINDOW_MOVED);
msg.AddInt32("window-x", (int)origin.x);
msg.AddInt32("window-y", (int)origin.y);
_PostWindowEvent(msg);
/* Perform normal hook operations */
BDirectWindow::FrameMoved(origin);
}
virtual void FrameResized(float width, float height) {
/* Post a message to the BApp so that it can handle the window event */
BMessage msg(BAPP_WINDOW_RESIZED);
msg.AddInt32("window-w", (int)width) + 1; /* TODO: Check that +1 is needed */
msg.AddInt32("window-h", (int)height) + 1;
_PostWindowEvent(msg);
/* Perform normal hook operations */
BDirectWindow::FrameResized(width, height);
}
virtual bool QuitRequested() {
BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED);
_PostWindowEvent(msg);
2011-07-25 16:46:55 +00:00
/* We won't allow a quit unless asked by DestroyWindow() */
return false;
}
virtual void WindowActivated(bool active) {
BMessage msg(BAPP_KEYBOARD_FOCUS); /* Mouse focus sold separately */
_PostWindowEvent(msg);
}
virtual void Zoom(BPoint origin,
float width,
float height) {
BMessage msg(BAPP_MAXIMIZE); /* Closest thing to maximization Haiku has */
_PostWindowEvent(msg);
/* Before the window zooms, record its size */
2011-07-25 16:46:55 +00:00
if( !_prev_frame )
_prev_frame = new BRect(Frame());
/* Perform normal hook operations */
BDirectWindow::Zoom(origin, width, height);
}
/* Member functions */
virtual void Show() {
2011-07-25 16:46:55 +00:00
while(IsHidden()) {
BDirectWindow::Show();
}
_shown = true;
2011-07-25 16:46:55 +00:00
BMessage msg(BAPP_SHOW);
_PostWindowEvent(msg);
}
virtual void Hide() {
BDirectWindow::Hide();
_shown = false;
2011-07-25 16:46:55 +00:00
BMessage msg(BAPP_HIDE);
_PostWindowEvent(msg);
}
virtual void Minimize(bool minimize) {
BDirectWindow::Minimize(minimize);
int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE);
BMessage msg(minState);
_PostWindowEvent(msg);
}
/* BView message interruption */
virtual void DispatchMessage(BMessage * msg, BHandler * target)
{
BPoint where; /* Used by mouse moved */
int32 buttons; /* Used for mouse button events */
int32 key; /* Used for key events */
switch (msg->what) {
case B_MOUSE_MOVED:
where;
int32 transit;
if (msg->FindPoint("where", &where) == B_OK
&& msg->FindInt32("be:transit", &transit) == B_OK) {
_MouseMotionEvent(where, transit);
}
/* FIXME: Apparently a button press/release event might be dropped
if made before before a different button is released. Does
B_MOUSE_MOVED have the data needed to check if a mouse button
state has changed? */
if (msg->FindInt32("buttons", &buttons) == B_OK) {
_MouseButtonEvent(buttons);
}
break;
case B_MOUSE_DOWN:
case B_MOUSE_UP:
/* _MouseButtonEvent() detects any and all buttons that may have
changed state, as well as that button's new state */
if (msg->FindInt32("buttons", &buttons) == B_OK) {
_MouseButtonEvent(buttons);
}
break;
case B_MOUSE_WHEEL_CHANGED:
float x, y;
if (msg->FindFloat("be:wheel_delta_x", &x) == B_OK
&& msg->FindFloat("be:wheel_delta_y", &y) == B_OK) {
_MouseWheelEvent((int)x, (int)y);
}
break;
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN: /* modifier keys are unmapped */
if (msg->FindInt32("key", &key) == B_OK) {
_KeyEvent((SDL_Scancode)key, SDL_PRESSED);
}
break;
case B_KEY_UP:
case B_UNMAPPED_KEY_UP: /* modifier keys are unmapped */
if (msg->FindInt32("key", &key) == B_OK) {
_KeyEvent(key, SDL_RELEASED);
}
break;
default:
/* move it after switch{} so it's always handled
that way we keep BeOS feautures like:
- CTRL+Q to close window (and other shortcuts)
- PrintScreen to make screenshot into /boot/home
- etc.. */
//BDirectWindow::DispatchMessage(msg, target);
break;
}
2011-07-25 16:46:55 +00:00
BDirectWindow::DispatchMessage(msg, target);
}
/* Handle command messages */
virtual void MessageReceived(BMessage* message) {
switch (message->what) {
/* Handle commands from SDL */
case BWIN_SET_TITLE:
_SetTitle(message);
break;
case BWIN_MOVE_WINDOW:
_MoveTo(message);
break;
case BWIN_RESIZE_WINDOW:
_ResizeTo(message);
break;
case BWIN_SHOW_WINDOW:
Show();
break;
case BWIN_HIDE_WINDOW:
Hide();
break;
case BWIN_MAXIMIZE_WINDOW:
BWindow::Zoom();
break;
case BWIN_MINIMIZE_WINDOW:
Minimize(true);
break;
case BWIN_RESTORE_WINDOW:
_Restore();
break;
case BWIN_FULLSCREEN:
_SetFullScreen(message);
break;
default:
/* Perform normal message handling */
BDirectWindow::MessageReceived(message);
break;
}
}
/* Accessor methods */
bool IsShown() { return _shown; }
int32 GetID() { return _id; }
2011-07-25 16:46:55 +00:00
void LockBuffer() { _buffer_locker->Lock(); }
void UnlockBuffer() { _buffer_locker->Unlock(); }
uint32 GetRowBytes() { return _row_bytes; }
2011-07-22 12:39:53 +00:00
int32 GetFbX() { return _bounds.left; }
int32 GetFbY() { return _bounds.top; }
int32 GetFbHeight() { return _bounds.bottom - _bounds.top + 1; }
int32 GetFbWidth() { return _bounds.right - _bounds.left + 1; }
2011-07-25 16:46:55 +00:00
bool ConnectionEnabled() { return !_connection_disabled; }
2011-07-22 12:39:53 +00:00
bool Connected() { return _connected; }
clipping_rect *GetClips() { return _clips; }
2011-07-25 16:46:55 +00:00
int32 GetNumClips() { return _num_clips; }
2011-07-22 12:39:53 +00:00
uint8* GetBufferPx() { return _bits; }
2011-07-25 16:46:55 +00:00
int32 GetBytesPerPx() { return _bytes_per_px; }
void SetWindowFramebuffer(uint8* fb) { _window_buffer = fb; }
uint8* GetWindowFramebuffer() { return _window_buffer; }
bool CanTrashWindowBuffer() { return _trash__window_buffer; }
/* Setter methods */
void SetID(int32 id) { _id = id; }
#if SDL_VIDEO_OPENGL
virtual void SwapBuffers(void)
{
2011-07-25 16:46:55 +00:00
_SDL_GLView->UnlockGL();
_SDL_GLView->LockGL();
_SDL_GLView->SwapBuffers();
}
#endif
virtual BView *View(void)
{
2011-07-25 16:46:55 +00:00
return (_the_view);
}
private:
/* Event redirection */
void _MouseMotionEvent(BPoint &where, int32 transit) {
if(transit == B_EXITED_VIEW) {
/* Change mouse focus */
2011-07-25 16:46:55 +00:00
if(_mouse_focused) {
_MouseFocusEvent(false);
}
} else {
static int x = 0, y = 0;
/* Change mouse focus */
2011-07-25 16:46:55 +00:00
if (!_mouse_focused) {
_MouseFocusEvent(true);
}
BMessage msg(BAPP_MOUSE_MOVED);
msg.AddInt32("dx", where.x - x);
msg.AddInt32("dy", where.y - y);
x = (int) where.x;
2011-07-25 16:46:55 +00:00
y = (int) where.y;
_PostWindowEvent(msg);
}
}
void _MouseFocusEvent(bool focusGained) {
2011-07-25 16:46:55 +00:00
_mouse_focused = focusGained;
BMessage msg(BAPP_MOUSE_FOCUS);
msg.AddBool("focusGained", focusGained);
_PostWindowEvent(msg);
//FIXME: Why were these here?
// if false: be_app->SetCursor(B_HAND_CURSOR);
// if true: SDL_SetCursor(NULL);
}
void _MouseButtonEvent(int32 buttons) {
2011-07-25 16:46:55 +00:00
int32 buttonStateChange = buttons ^ _last_buttons;
/* Make sure at least one button has changed state */
if( !(buttonStateChange) ) {
return;
}
/* Add any mouse button events */
if(buttonStateChange & B_PRIMARY_MOUSE_BUTTON) {
2011-07-20 19:25:38 +00:00
_SendMouseButton(SDL_BUTTON_LEFT, buttons &
B_PRIMARY_MOUSE_BUTTON);
}
if(buttonStateChange & B_SECONDARY_MOUSE_BUTTON) {
2011-07-20 19:25:38 +00:00
_SendMouseButton(SDL_BUTTON_RIGHT, buttons &
B_PRIMARY_MOUSE_BUTTON);
}
if(buttonStateChange & B_TERTIARY_MOUSE_BUTTON) {
2011-07-20 19:25:38 +00:00
_SendMouseButton(SDL_BUTTON_MIDDLE, buttons &
B_PRIMARY_MOUSE_BUTTON);
}
2011-07-25 16:46:55 +00:00
_last_buttons = buttons;
}
void _SendMouseButton(int32 button, int32 state) {
BMessage msg(BAPP_MOUSE_BUTTON);
msg.AddInt32("button-id", button);
msg.AddInt32("button-state", state);
_PostWindowEvent(msg);
}
void _MouseWheelEvent(int32 x, int32 y) {
/* Create a message to pass along to the BeApp thread */
BMessage msg(BAPP_MOUSE_WHEEL);
msg.AddInt32("xticks", x);
msg.AddInt32("yticks", y);
_PostWindowEvent(msg);
}
void _KeyEvent(int32 keyCode, int32 keyState) {
/* Create a message to pass along to the BeApp thread */
BMessage msg(BAPP_KEY);
msg.AddInt32("key-state", keyState);
msg.AddInt32("key-scancode", keyCode);
be_app->PostMessage(&msg);
/* Apparently SDL only uses the scancode */
}
void _RepaintEvent() {
/* Force a repaint: Call the SDL exposed event */
BMessage msg(BAPP_REPAINT);
_PostWindowEvent(msg);
}
void _PostWindowEvent(BMessage &msg) {
msg.AddInt32("window-id", _id);
be_app->PostMessage(&msg);
}
/* Command methods (functions called upon by SDL) */
void _SetTitle(BMessage *msg) {
const char *title;
if(
msg->FindString("window-title", &title) != B_OK
) {
return;
}
SetTitle(title);
}
void _MoveTo(BMessage *msg) {
int32 x, y;
if(
msg->FindInt32("window-x", &x) != B_OK ||
msg->FindInt32("window-y", &y) != B_OK
) {
return;
}
MoveTo(x, y);
}
void _ResizeTo(BMessage *msg) {
int32 w, h;
if(
msg->FindInt32("window-w", &w) != B_OK ||
msg->FindInt32("window-h", &h) != B_OK
) {
return;
}
ResizeTo(w, h);
}
void _Restore() {
if(IsMinimized()) {
Minimize(false);
} else if(IsHidden()) {
Show();
2011-07-25 16:46:55 +00:00
} else if(_prev_frame != NULL) { /* Zoomed */
MoveTo(_prev_frame->left, _prev_frame->top);
ResizeTo(_prev_frame->Width(), _prev_frame->Height());
}
}
void _SetFullScreen(BMessage *msg) {
bool fullscreen;
if(
msg->FindBool("fullscreen", &fullscreen) != B_OK
) {
return;
}
SetFullScreen(fullscreen);
}
/* Members */
#if SDL_VIDEO_OPENGL
2011-07-25 16:46:55 +00:00
BGLView * _SDL_GLView;
#endif
2011-07-25 16:46:55 +00:00
BView *_the_view;
2011-07-25 16:46:55 +00:00
int32 _last_buttons;
int32 _id; /* Window id used by SDL_BApp */
2011-07-25 16:46:55 +00:00
bool _mouse_focused; /* Does this window have mouse focus? */
bool _shown;
bool _inhibit_resize;
2011-07-25 16:46:55 +00:00
BRect *_prev_frame; /* Previous position and size of the window */
2011-07-22 12:39:53 +00:00
/* Framebuffer members */
2011-07-25 16:46:55 +00:00
bool _connected, _connection_disabled;
uint8 *_bits;
uint32 _row_bytes;
2011-07-22 12:39:53 +00:00
clipping_rect _bounds;
2011-07-25 16:46:55 +00:00
BLocker *_buffer_locker;
clipping_rect *_clips;
int32 _num_clips;
int32 _bytes_per_px;
uint8 *_window_buffer; /* A copy of the window buffer */
bool _trash__window_buffer;
};
#endif