mutter/clutter/fruity/clutter-fruity.c

444 lines
11 KiB
C
Raw Normal View History

#include <clutter/clutter.h>
#include "clutter-backend-fruity.h"
#include "clutter-stage-fruity.h"
#include "../clutter-main.h"
#include "../clutter-private.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#include <GraphicsServices/GraphicsServices.h>
#include <OpenGLES/gl.h>
#include <glib.h>
#import <UIKit/UIView.h>
#import <UIKit/UITextView.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UINavigationBar.h>
#import <UIKit/UIView-Geometry.h>
#include "clutter-fruity.h"
static gboolean alive = TRUE;
@interface StageView : UIView
{
}
@end
@implementation StageView
struct GSPathPoint {
char unk0;
char unk1;
short int status;
int unk2;
float x;
float y;
};
typedef struct {
int unk0;
int unk1;
int type;
int subtype;
float unk2;
float unk3;
float x;
float y;
int timestamp1;
int timestamp2;
int unk4;
int modifierFlags;
int unk5;
int unk6;
int mouseEvent;
short int dx;
short int fingerCount;
int unk7;
int unk8;
char unk9;
char numPoints;
short int unk10;
struct GSPathPoint points[10];
} MEvent;
#define MAX_FINGERS 5
- (void)doEvent:(GSEvent*)gs_event
{
ClutterBackendEGL *ba = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
int i, j;
ClutterMainContext *context;
ClutterStage *stage = CLUTTER_STAGE_EGL(ba->stage)->wrapper;
MEvent *event = (MEvent*)gs_event;
context = _clutter_context_get_default ();
bool mapped[MAX_FINGERS] = {false, false, false, false, false}; /* an event has been mapped to this device */
int evs[MAX_FINGERS] = {0,0,0,0,0};
/* using numPoints (with the points[i].status check) seems to
* be no different from using numFingers :/ */
for (i = 0; i < event->numPoints; i++)
{
bool found = false;
if (event->points[i].status != 3) /* skip if finger not down */
continue;
/* NSLog(@"IncomingEvent: %d, pos: %f, %f", i, event->points[i].x, event->points[i].y);*/
/* check if this finger maps to one of the existing devices */
for (j = 0; j < MAX_FINGERS; j++)
{
ClutterFruityFingerDevice *dev;
if (mapped[j])
continue; /* we're already using device j */
dev = g_slist_nth_data (context->input_devices, j);
if (!dev->is_down)
continue; /* device isn't down we cannot really match against it */
int dist = (event->points[i].x - dev->x) * (event->points[i].x - dev->x) +
(event->points[i].y - dev->y) * (event->points[i].y - dev->y);
if (dist < 20 * 20)
{
found = true;
mapped[j] = true;
/* only generate motion events if we've changed position */
if (dist >= 1)
{
dev->x = event->points[i].x;
dev->y = event->points[i].y;
// MOUSEMOVE
/*NSLog(@"MouseMove: %d, pos: %d, %d", j, dev->x, dev->y);*/
evs[j] = 3;
}
break;
}
}
if (!found)
{
ClutterFruityFingerDevice *dev;
for (j = 0; j < MAX_FINGERS; j++)
{
dev = g_slist_nth_data (context->input_devices, j);
if (!dev->is_down)
break;
}
dev->x = event->points[i].x;
dev->y = event->points[i].y;
g_assert (dev->is_down == FALSE);
dev->is_down = TRUE;
mapped[j] = true;
// MOUSEDOWN
/* NSLog(@"MouseDown: %d, pos: %d, %d", j, event->points[i].x, dev->x, dev->y); */
evs[j] = 2;
}
}
for (j = 0; j < MAX_FINGERS; j++)
{
ClutterFruityFingerDevice *dev;
dev = g_slist_nth_data (context->input_devices, j);
if (dev->is_down && !mapped[j])
{
// MOUSEUP
/* NSLog(@"MouseUp: %d, pos: %d, %d", j, dev->x, dev->y); */
evs[j] = 1;
dev->is_down = FALSE;
}
}
/* Now I guess go through device list and deliver an event for each
* if valid and devliver if so...
*/
{
i = 0;
GSList *list_it;
for (list_it = context->input_devices;
list_it != NULL;
list_it = list_it->next)
{
ClutterFruityFingerDevice *dev = (ClutterFruityFingerDevice *)list_it->data;
if (evs[i] > 0)
{
ClutterEvent *cev;
if (evs[i] == 1)
{
cev = clutter_event_new (CLUTTER_BUTTON_RELEASE);
cev->button.device = (ClutterInputDevice *)dev;
cev->button.x = dev->x;
cev->button.y = dev->y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
else if (evs[i] == 2)
{
cev = clutter_event_new (CLUTTER_BUTTON_PRESS);
cev->button.device = (ClutterInputDevice *)dev;
cev->button.x = dev->x;
cev->button.y = dev->y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
else /* evs = 3, motion */
{
cev = clutter_event_new (CLUTTER_MOTION);
cev->motion.device = (ClutterInputDevice *)dev;
cev->motion.x = dev->x;
cev->motion.y = dev->y;
cev->motion.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
}
i++;
}
}
}
#if 0 // old style
- (void) mouseDown:(GSEvent*)event
{
CGPoint location= GSEventGetLocationInWindow(event);
ClutterBackendEGL *backend_fruity = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
ClutterStage *stage = CLUTTER_STAGE_EGL(backend_fruity->stage)->wrapper;
ClutterEvent *cev;
float x = location.x;
float y = location.y;
cev = clutter_event_new (CLUTTER_BUTTON_PRESS);
cev->button.x = x;
cev->button.y = y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
- (void) mouseUp:(GSEvent*)event
{
ClutterEvent *cev;
ClutterBackendEGL *backend_fruity = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
ClutterStage *stage = CLUTTER_STAGE_EGL(backend_fruity->stage)->wrapper;
CGPoint location= GSEventGetLocationInWindow(event);
float x = location.x;
float y = location.y;
cev = clutter_event_new (CLUTTER_BUTTON_RELEASE);
cev->button.x = x;
cev->button.y = y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
- (void) mouseDragged:(GSEvent*)event
{
ClutterEvent *cev;
ClutterBackendEGL *backend_fruity = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
ClutterStage *stage = CLUTTER_STAGE_EGL(backend_fruity->stage)->wrapper;
CGPoint location= GSEventGetLocationInWindow(event);
float x = location.x;
float y = location.y;
cev = clutter_event_new (CLUTTER_MOTION);
cev->motion.x = x;
cev->motion.y = y;
cev->motion.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
#endif
/* New... */
#if 0
- (void)gestureChanged:(GSEvent*)event {
NSLog(@"gestureChanged:");
[self doEvent: event];
}
- (void)gestureEnded:(GSEvent*)event {
NSLog(@"gestureEnded:");
[self doEvent: event];
}
- (void)gestureStarted:(GSEvent*)event {
/*NSLog(@"gestureStarted:");*/
[self doEvent: event];
}
#endif
- (void)mouseDown:(GSEvent*)event {
/*NSLog(@"mouseDown:");*/
[self doEvent: event];
}
- (void)mouseDragged:(GSEvent*)event {
/*NSLog(@"mouseDragged:");*/
[self doEvent: event];
}
- (void)mouseEntered:(GSEvent*)event {
/*NSLog(@"mouseEntered:");*/
[self doEvent: event];
}
- (void)mouseExited:(GSEvent*)event {
/*NSLog(@"mouseExited:");*/
[self doEvent: event];
}
- (void)mouseMoved:(GSEvent*)event {
/*NSLog(@"mouseMoved:");*/
[self doEvent: event];
}
- (void)mouseUp:(GSEvent*)event {
/*NSLog(@"mouseUp:");*/
[self doEvent: event];
}
- (void)view:(UIView *)view handleTapWithCount:(int)count event:(GSEvent *)event {
/*NSLog(@"handleTapWithCount: %d", count);*/
[self doEvent: event];
}
- (double)viewTouchPauseThreshold:(UIView *)view {
return 0.5;
}
- (BOOL)isFirstResponder {
return YES;
}
@end
@interface ClutterUIKit : UIApplication
{
StageView *stage_view;
}
@end
@implementation ClutterUIKit
- (void) applicationDidFinishLaunching: (id) unused
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[UIHardware _setStatusBarHeight:0.0f];
[self setStatusBarMode:2 orientation:0 duration:0.0f fenceID:0];
CGRect screenRect = [UIHardware fullScreenApplicationContentRect];
UIWindow* window = [[UIWindow alloc] initWithContentRect: screenRect];
[window orderFront: self];
[window makeKey: self];
[window _setHidden: NO];
[NSTimer
scheduledTimerWithTimeInterval:0.0025
target: self
selector: @selector(update)
userInfo: nil
repeats: YES
];
StageView *stageView = [StageView alloc];
[stageView initWithFrame: screenRect];
[window setContentView: stageView];
stage_view = stageView;
[pool release];
}
- (void)applicationWillTerminate
{
/* FIXME: here we should do things to shut down the uikit application */
[stage_view release];
ClutterBackendEGL *backend_fruity = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
ClutterStageEGL *stage_fruity;
stage_fruity = CLUTTER_STAGE_EGL(backend_fruity->stage);
alive = FALSE;
Enforce invariants on mapped, realized, visibility states Bug 1138 - No trackable "mapped" state * Add a VISIBLE flag tracking application programmer's expected showing-state for the actor, allowing us to always ensure we keep what the app wants while tracking internal implementation state separately. * Make MAPPED reflect whether the actor will be painted; add notification on a ClutterActor::mapped property. Keep MAPPED state updated as the actor is shown, ancestors are shown, actor is reparented, etc. * Require a stage and realized parents to realize; this means at realization time the correct window system and GL resources are known. But unparented actors can no longer be realized. * Allow children to be unrealized even if parent is realized. Otherwise in effect either all actors or no actors are realized, i.e. it becomes a stage-global flag. * Allow clutter_actor_realize() to "fail" if not inside a toplevel * Rework clutter_actor_unrealize() so internally we have a flavor that does not mess with visibility flag * Add _clutter_actor_rerealize() to encapsulate a somewhat tricky operation we were doing in a couple of places * Do not realize/unrealize children in ClutterGroup, ClutterActor already does it * Do not realize impl by hand in clutter_stage_show(), since showing impl already does that * Do not unrealize in various dispose() methods, since ClutterActor dispose implementation already does it and chaining up is mandatory * ClutterTexture uses COGL while unrealizable (before it's added to a stage). Previously this breakage was affecting ClutterActor because we had to allow realize outside a stage. Move the breakage to ClutterTexture, by making ClutterTexture just use COGL while not realized. * Unrealize before we set parent to NULL in clutter_actor_unparent(). This means unrealize() implementations can get to the stage. Because actors need the stage in order to detach from stage. * Update clutter-actor-invariants.txt to reflect latest changes * Remove explicit hide/unrealize from ClutterActor::dispose since unparent already forces those Instead just assert that unparent() occurred and did the right thing. * Check whether parent implements unrealize before chaining up Needed because ClutterGroup no longer has to implement unrealize. * Perform unrealize in the default handler for the signal. This allows non-containers that have children to work properly, and allows containers to override how it's done. * Add map/unmap virtual methods and set MAPPED flag on self and children in there. This allows subclasses to hook map/unmap. These are not signals, because notify::mapped is better for anything it's legitimate for a non-subclass to do. Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
2009-04-02 13:16:43 +00:00
/* FIXME why is this unrealize here? is the intent to destroy the stage?
* or hide it? Trying to clean up all manual unrealization so
* clutter_actor_unrealize() can be made private to clutter-actor.c
*/
clutter_actor_unrealize (CLUTTER_ACTOR (stage_fruity));
clutter_main_quit ();
}
- (void)applicationWillSuspend
{
ClutterBackendEGL *backend_fruity = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
ClutterStageEGL *stage_fruity;
stage_fruity = CLUTTER_STAGE_EGL(backend_fruity->stage);
alive = FALSE;
}
- (void)applicationDidResumeFromUnderLock
{
alive = TRUE;
[stage_view setNeedsDisplay];
}
- (void) update
{
if (alive && g_main_context_pending (NULL))
g_main_context_iteration (NULL, FALSE);
}
- (id)initWithFrame:(struct CGRect)frame {
[super initWithFrame: frame];
[super setTapDelegate: self];
[super setGestureDelegate: self];
return self;
}
@end
void clutter_fruity_main (void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIApplicationMain(0, NULL, [ClutterUIKit class]);
[pool release];
}