From b1847959b19d8474bbc1205ce1a0d64240e8dbcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Sandmann?= Date: Sat, 25 Feb 2006 16:54:39 +0000 Subject: [PATCH] Call meta_compositor_begin_move if there is a compositor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sat Feb 25 11:46:14 2006 Søren Sandmann * src/display.c (meta_display_begin_grab_op): Call meta_compositor_begin_move if there is a compositor * src/compositor.c (meta_compositor_begin/update/end_move): Implement those functions. * src/spring-model.[ch]: New files --- ChangeLog | 10 + src/Makefile.am | 2 + src/compositor.c | 552 +++++++++++++++++++-------------------------- src/compositor.h | 10 + src/display.c | 21 +- src/spring-model.c | 410 +++++++++++++++++++++++++++++++++ src/spring-model.h | 31 +++ src/window.c | 65 +++--- 8 files changed, 747 insertions(+), 354 deletions(-) create mode 100644 src/spring-model.c create mode 100644 src/spring-model.h diff --git a/ChangeLog b/ChangeLog index 60e66150b..8954e5dd2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Sat Feb 25 11:46:14 2006 Søren Sandmann + + * src/display.c (meta_display_begin_grab_op): Call + meta_compositor_begin_move if there is a compositor + + * src/compositor.c (meta_compositor_begin/update/end_move): + Implement those functions. + + * src/spring-model.[ch]: New files + Thu Feb 23 15:40:52 2006 Søren Sandmann * src/compositor.c (meta_compositor_manage_screen): Don't attempt diff --git a/src/Makefile.am b/src/Makefile.am index efbc0b251..110614e70 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,6 +70,8 @@ metacity_SOURCES= \ screen.h \ session.c \ session.h \ + spring-model.c \ + spring-model.h \ stack.c \ stack.h \ tabpopup.c \ diff --git a/src/compositor.c b/src/compositor.c index 46c57e213..17e17d0ce 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -32,7 +32,6 @@ #ifdef HAVE_COMPOSITE_EXTENSIONS #include #include - #include #include #include @@ -45,6 +44,7 @@ #include #include #include +#include "spring-model.h" #endif /* HAVE_COMPOSITE_EXTENSIONS */ #define FRAME_INTERVAL_MILLISECONDS ((int)(1000.0/40.0)) @@ -59,6 +59,8 @@ typedef struct int idle_id; } ScreenInfo; +typedef struct MoveInfo MoveInfo; + struct MetaCompositor { MetaDisplay *meta_display; @@ -77,6 +79,8 @@ struct MetaCompositor guint debug_updates : 1; GList *ignored_damage; + + MoveInfo *move_info; }; #endif /* HAVE_COMPOSITE_EXTENSIONS */ @@ -105,7 +109,7 @@ meta_compositor_new (MetaDisplay *display) gboolean has_extensions; compositor_display = ws_display_new (NULL); - + has_extensions = ws_display_init_composite (compositor_display) && ws_display_init_damage (compositor_display) && @@ -120,7 +124,7 @@ meta_compositor_new (MetaDisplay *display) return NULL; } - + ws_display_set_ignore_grabs (compositor_display, TRUE); } @@ -132,10 +136,10 @@ meta_compositor_new (MetaDisplay *display) compositor->meta_display = display; compositor->window_hash = - g_hash_table_new_full (meta_unsigned_long_hash, - meta_unsigned_long_equal, - NULL, - free_window_hash_value); + g_hash_table_new_full (meta_unsigned_long_hash, + meta_unsigned_long_equal, + NULL, + free_window_hash_value); compositor->enabled = TRUE; @@ -296,6 +300,11 @@ process_configure_notify (MetaCompositor *compositor, &event->above); } +#if 0 + cm_drawable_node_set_size (node, + event->x, event->y, event->width, event->height); +#endif + handle_restacking (compositor, node, above_node); } #endif /* HAVE_COMPOSITE_EXTENSIONS */ @@ -757,10 +766,8 @@ update (gpointer data) glEnd (); #endif -#if 0 glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); -#endif #if 0 glEnable (GL_TEXTURE_2D); @@ -973,9 +980,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor, Display *xdisplay; Atom cm_sn_atom; char buf[128]; - + if (screen->compositor_data) - return; + return; scr_info->glw = ws_screen_get_gl_window (ws_screen); scr_info->compositor_nodes = NULL; @@ -987,7 +994,7 @@ meta_compositor_manage_screen (MetaCompositor *compositor, ws_display_init_composite (compositor->display); ws_display_init_damage (compositor->display); ws_display_init_fixes (compositor->display); - + g_print ("redirecting\n"); ws_window_redirect_subwindows (root); ws_window_set_override_redirect (scr_info->glw, TRUE); @@ -1046,11 +1053,11 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor, } ws_window_raise (scr_info->glw); - + g_print ("unredirecting\n"); ws_window_unredirect_subwindows (root); ws_window_unmap (scr_info->glw); - + /* We need to sync here, because if someone is furiously * clicking the 'compositing manager' check box, we might * attempt to redirect the window again before this unredirect @@ -1175,7 +1182,7 @@ interpolate_rectangle (gdouble t, #endif -#define MINIMIZE_STYLE 1 +#define MINIMIZE_STYLE 3 #ifndef HAVE_COMPOSITE_EXTENSIONS #undef MINIMIZE_STYLE @@ -1236,10 +1243,12 @@ set_geometry (MiniInfo *info, gdouble elapsed) interpolate_rectangle (elapsed, &info->current_geometry, &info->target_geometry, &rect); +#if 0 g_print ("y: %d %d (%f => %d)\n", info->current_geometry.y, info->target_geometry.y, elapsed, rect.y); g_print ("setting: %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height); +#endif cm_drawable_node_set_geometry (info->node, rect.x, rect.y, @@ -1412,7 +1421,7 @@ run_animation_01 (gpointer data) { cm_drawable_node_set_viewable (info->node, FALSE); - cm_drawable_node_unset_geometry (info->node); + cm_drawable_node_unset_geometry (info->node); cm_drawable_node_set_alpha (info->node, 1.0); @@ -1540,65 +1549,6 @@ do_minimize_animation (gpointer data) #elif MINIMIZE_STYLE == 3 - -typedef struct XYPair Point; -typedef struct XYPair Vector; -typedef struct Spring Spring; -typedef struct Object Object; -typedef struct Model Model; - -struct XYPair { - double x, y; -}; - -#define GRID_WIDTH 4 -#define GRID_HEIGHT 4 - -#define MODEL_MAX_OBJECTS (GRID_WIDTH * GRID_HEIGHT) -#define MODEL_MAX_SPRINGS (MODEL_MAX_OBJECTS * 2) - -#define DEFAULT_SPRING_K 5.0 -#define DEFAULT_FRICTION 1.4 - -struct Spring { - Object *a; - Object *b; - /* Spring position at rest, from a to b: - offset = b.position - a.position - */ - Vector offset; -}; - -struct Object { - Vector force; - - Point position; - Vector velocity; - - double mass; - double theta; - - int immobile; -}; - -struct Model { - int num_objects; - Object objects[MODEL_MAX_OBJECTS]; - - int num_springs; - Spring springs[MODEL_MAX_SPRINGS]; - - Object *anchor_object; - Vector anchor_offset; - - double friction;/* Friction constant */ - double k;/* Spring constant */ - - double last_time; - double steps; -}; - - typedef struct { CmDrawableNode *node; @@ -1606,13 +1556,14 @@ typedef struct gboolean expand; MetaCompositor *compositor; - ScreenInfo *scr_info; + MetaScreen *screen; MetaRectangle rect; + double last_time; MetaAnimationFinishedFunc finished_func; gpointer finished_data; - Model model; + Model *model; int button_x; int button_y; @@ -1620,270 +1571,96 @@ typedef struct int button_height; } MiniInfo; -static void -object_init (Object *object, - double position_x, double position_y, - double velocity_x, double velocity_y, double mass) -{ - object->position.x = position_x; - object->position.y = position_y; - - object->velocity.x = velocity_x; - object->velocity.y = velocity_y; - - object->mass = mass; - - object->force.x = 0; - object->force.y = 0; - - object->immobile = 0; -} - -static void -spring_init (Spring *spring, - Object *object_a, Object *object_b, - double offset_x, double offset_y) -{ - spring->a = object_a; - spring->b = object_b; - spring->offset.x = offset_x; - spring->offset.y = offset_y; -} - -static void -model_add_spring (Model *model, - Object *object_a, Object *object_b, - double offset_x, double offset_y) -{ - Spring *spring; - - g_assert (model->num_springs < MODEL_MAX_SPRINGS); - - spring = &model->springs[model->num_springs]; - model->num_springs++; - - spring_init (spring, object_a, object_b, offset_x, offset_y); -} - -static void -model_init_grid (Model *model, MetaRectangle *rect, gboolean expand) -{ - int x, y, i, v_x, v_y; - int hpad, vpad; - - model->num_objects = MODEL_MAX_OBJECTS; - - model->num_springs = 0; - - i = 0; - if (expand) { - hpad = rect->width / 3; - vpad = rect->height / 3; - } - else { - hpad = rect->width / 6; - vpad = rect->height / 6; - } - - for (y = 0; y < GRID_HEIGHT; y++) - for (x = 0; x < GRID_WIDTH; x++) { - - v_x = random() % 40 - 20; - v_y = random() % 40 - 20; - - if (expand) - object_init (&model->objects[i], - rect->x + x * rect->width / 6 + rect->width / 4, - rect->y + y * rect->height / 6 + rect->height / 4, - v_x, v_y, 20); - else - object_init (&model->objects[i], - rect->x + x * rect->width / 3, - rect->y + y * rect->height / 3, - v_x, v_y, 20); - - - if (x > 0) - model_add_spring (model, - &model->objects[i - 1], - &model->objects[i], - hpad, 0); - - if (y > 0) - model_add_spring (model, - &model->objects[i - GRID_WIDTH], - &model->objects[i], - 0, vpad); - - i++; - } -} - -static void -model_init (Model *model, MetaRectangle *rect, gboolean expand) -{ - model->anchor_object = NULL; - - model->k = DEFAULT_SPRING_K; - model->friction = DEFAULT_FRICTION; - - model_init_grid (model, rect, expand); - model->steps = 0; - model->last_time = 0; -} - -static void -object_apply_force (Object *object, double fx, double fy) -{ - object->force.x += fx; - object->force.y += fy; -} - -/* The model here can be understood as a rigid body of the spring's - * rest shape, centered on the vector between the two object - * positions. This rigid body is then connected by linear-force - * springs to each object. This model does degnerate into a simple - * spring for linear displacements, and does something reasonable for - * rotation. - * - * There are other possibilities for handling the rotation of the - * spring, and it might be interesting to explore something which has - * better length-preserving properties. For example, with the current - * model, an initial 180 degree rotation of the spring results in the - * spring collapsing down to 0 size before expanding back to it's - * natural size again. - */ - -static void -spring_exert_forces (Spring *spring, double k) -{ - Vector da, db; - Vector a, b; - - a = spring->a->position; - b = spring->b->position; - - /* A nice vector diagram would likely help here, but my ASCII-art - * skills aren't up to the task. Here's how to make your own - * diagram: - * - * Draw a and b, and the vector AB from a to b - * Find the center of AB - * Draw spring->offset so that its center point is on the center of AB - * Draw da from a to the initial point of spring->offset - * Draw db from b to the final point of spring->offset - * - * The math below should be easy to verify from the diagram. - */ - - da.x = 0.5 * (b.x - a.x - spring->offset.x); - da.y = 0.5 * (b.y - a.y - spring->offset.y); - - db.x = 0.5 * (a.x - b.x + spring->offset.x); - db.y = 0.5 * (a.y - b.y + spring->offset.y); - - object_apply_force (spring->a, k *da.x, k * da.y); - - object_apply_force (spring->b, k * db.x, k * db.y); -} - -static void -model_step_object (Model *model, Object *object) -{ - Vector acceleration; - - object->theta += 0.05; - - /* Slow down due to friction. */ - object->force.x -= model->friction * object->velocity.x; - object->force.y -= model->friction * object->velocity.y; - - acceleration.x = object->force.x / object->mass; - acceleration.y = object->force.y / object->mass; - - if (object->immobile) { - object->velocity.x = 0; - object->velocity.y = 0; - } else { - object->velocity.x += acceleration.x; - object->velocity.y += acceleration.y; - - object->position.x += object->velocity.x; - object->position.y += object->velocity.y; - } - - object->force.x = 0.0; - object->force.y = 0.0; -} - -static void -model_step (Model *model) -{ - int i; - - for (i = 0; i < model->num_springs; i++) - spring_exert_forces (&model->springs[i], model->k); - - for (i = 0; i < model->num_objects; i++) - model_step_object (model, &model->objects[i]); -} - #define WOBBLE_TIME 1.0 +static void +set_patch (CmDrawableNode *node, + Model *model, + gdouble blend, + MetaRectangle *target) +{ + int i, j; + CmPoint points[4][4]; + + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + { + double obj_x, obj_y; + int p_x, p_y; + + model_get_position (model, i, j, &obj_x, &obj_y); + +#if 0 + target_x = info->node->real_x + i * info->node->real_width / 3; + target_y = info->node->real_y + j * info->node->real_height / 3; +#endif + if (target) + { + p_x = target->x + i * target->width / 3; + p_y = target->y + j * target->height / 3; + + points[j][i].x = (1 - blend) * obj_x + blend * p_x; + points[j][i].y = (1 - blend) * obj_y + blend * p_y; + } + else + { + points[j][i].x = obj_x; + points[j][i].y = obj_y; + } + } + + cm_drawable_node_set_patch (node, points); +} + static gboolean run_animation (gpointer data) { MiniInfo *info = data; gdouble t, blend; - CmPoint points[4][4]; - int i, j, steps, target_x, target_y; + double n_steps; + int i; t = g_timer_elapsed (info->timer, NULL); - info->model.steps += (t - info->model.last_time) / 0.03; - info->model.last_time = t; - steps = floor(info->model.steps); - info->model.steps -= steps; + n_steps = floor ((t - info->last_time) * 75); - for (i = 0; i < steps; i++) - model_step (&info->model); + for (i = 0; i < n_steps; ++i) + model_step (info->model); - if (info->expand) - blend = t / WOBBLE_TIME; - else - blend = 0; + if (i > 0) + info->last_time = t; - for (i = 0; i < 4; i++) - for (j = 0; j < 4; j++) { - target_x = info->node->real_x + i * info->node->real_width / 3; - target_y = info->node->real_y + j * info->node->real_height / 3; - - points[j][i].x = - (1 - blend) * info->model.objects[j * 4 + i].position.x + - blend * target_x; - points[j][i].y = - (1 - blend) * info->model.objects[j * 4 + i].position.y + - blend * target_y; - } + blend = t / WOBBLE_TIME; + + set_patch (info->node, info->model, 0.0, NULL); - cm_drawable_node_set_patch (info->node, points); if (info->expand) cm_drawable_node_set_alpha (info->node, t / WOBBLE_TIME); else cm_drawable_node_set_alpha (info->node, 1.0 - t / WOBBLE_TIME); - if (t > WOBBLE_TIME) { - cm_drawable_node_set_viewable (info->node, info->expand); - cm_drawable_node_unset_geometry (info->node); - cm_drawable_node_set_alpha (info->node, 1.0); - - if (info->finished_func) - info->finished_func (info->finished_data); - return FALSE; - } - else { - return TRUE; - } + if (t > WOBBLE_TIME) + { + cm_drawable_node_set_viewable (info->node, info->expand); + cm_drawable_node_unset_geometry (info->node); + cm_drawable_node_set_alpha (info->node, 1.0); + + if (info->finished_func) + { + info->finished_func (info->finished_data); + + model_destroy (info->model); + info->model = NULL; + } + + return FALSE; + } + else + { + queue_repaint (info->node, info->screen); + + return TRUE; + } } void @@ -1909,7 +1686,9 @@ meta_compositor_minimize (MetaCompositor *compositor, info->rect = window->user_rect; - model_init (&info->model, &info->rect, FALSE); + info->model = model_new (&info->rect, FALSE); + + info->last_time = 0.0; info->expand = FALSE; info->button_x = x; @@ -1918,7 +1697,7 @@ meta_compositor_minimize (MetaCompositor *compositor, info->button_height = height; info->compositor = compositor; - info->scr_info = screen->compositor_data; + info->screen = screen; g_idle_add (run_animation, info); #endif @@ -1947,7 +1726,7 @@ meta_compositor_unminimize (MetaCompositor *compositor, info->rect = window->user_rect; - model_init (&info->model, &info->rect, TRUE); + info->model = model_new (&info->rect, TRUE); info->expand = TRUE; info->button_x = x; @@ -1956,7 +1735,7 @@ meta_compositor_unminimize (MetaCompositor *compositor, info->button_height = height; info->compositor = compositor; - info->scr_info = screen->compositor_data; + info->screen = screen; g_idle_add (run_animation, info); #endif @@ -2052,7 +1831,9 @@ void meta_compositor_destroy (MetaCompositor *compositor) { #ifdef HAVE_COMPOSITE_EXTENSIONS +#if 0 GSList *list; +#endif #if 0 /* FIXME */ @@ -2064,3 +1845,122 @@ meta_compositor_destroy (MetaCompositor *compositor) g_free (compositor); #endif } + +#ifdef HAVE_COMPOSITE_EXTENSIONS + +struct MoveInfo +{ + GTimer *timer; + gboolean finished; + Model *model; + MetaScreen *screen; + CmDrawableNode *node; + gdouble last_time; +}; + +#endif + +#ifdef HAVE_COMPOSITE_EXTENSIONS + +static gboolean +wobble (gpointer data) +{ + MoveInfo *info = data; + double t = g_timer_elapsed (info->timer, NULL); + + if (info->finished && model_is_calm (info->model)) + { + cm_drawable_node_unset_geometry (info->node); + g_free (info); + info = NULL; + return FALSE; + } + else + { + int i; + int n_steps; + n_steps = floor ((t - info->last_time) * 75); + + for (i = 0; i < n_steps; ++i) + model_step (info->model); + + if (i > 0) + info->last_time = t; + + set_patch (info->node, info->model, 0.0, NULL); + + queue_repaint (info->node, info->screen); + return TRUE; + } +} + +#endif + +static void +compute_window_rect (MetaWindow *window, + MetaRectangle *rect) +{ + /* FIXME: does metacity include this function somewhere? */ + + if (window->frame) + { + *rect = window->frame->rect; + } + else + { + *rect = window->user_rect; + } +} + +void +meta_compositor_begin_move (MetaCompositor *compositor, + MetaWindow *window, + MetaRectangle *initial, + int grab_x, int grab_y) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + MetaRectangle rect; + + compositor->move_info = g_new0 (MoveInfo, 1); + + compositor->move_info->last_time = 0.0; + compositor->move_info->timer = g_timer_new (); + + compute_window_rect (window, &rect); + +#if 0 + g_print ("init: %d %d\n", initial->x, initial->y); + g_print ("window: %d %d\n", window->rect.x, window->rect.y); + g_print ("frame: %d %d\n", rect.x, rect.y); + g_print ("grab: %d %d\n", grab_x, grab_y); +#endif + + compositor->move_info->model = model_new (&rect, TRUE); + compositor->move_info->node = window_to_node (window->display->compositor, window); + compositor->move_info->screen = window->screen; + + model_begin_move (compositor->move_info->model, grab_x, grab_y); + + g_idle_add (wobble, compositor->move_info); +#endif +} + +void +meta_compositor_update_move (MetaCompositor *compositor, + MetaWindow *window, + int x, int y) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + model_update_move (compositor->move_info->model, x, y); +#endif +} + +void +meta_compositor_end_move (MetaCompositor *compositor, + MetaWindow *window) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + compositor->move_info->finished = TRUE; + compositor->move_info = NULL; +#endif +} diff --git a/src/compositor.h b/src/compositor.h index f404f6398..1d731411a 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -70,4 +70,14 @@ meta_compositor_set_updates (MetaCompositor *compositor, void meta_compositor_destroy (MetaCompositor *compositor); +void meta_compositor_begin_move (MetaCompositor *compositor, + MetaWindow *window, + MetaRectangle *initial, + int grab_x, int grab_y); +void meta_compositor_update_move (MetaCompositor *compositor, + MetaWindow *window, + int x, int y); +void meta_compositor_end_move (MetaCompositor *compositor, + MetaWindow *window); + #endif /* META_COMPOSITOR_H */ diff --git a/src/display.c b/src/display.c index ce349fb06..e1145a090 100644 --- a/src/display.c +++ b/src/display.c @@ -1835,7 +1835,7 @@ event_callback (XEvent *event, XAllowEvents (display->xdisplay, mode, event->xbutton.time); } - + if (begin_move && window->has_move_func) { meta_display_begin_grab_op (display, @@ -3305,6 +3305,16 @@ meta_display_begin_grab_op (MetaDisplay *display, { Window grab_xwindow; + if (grab_op_is_mouse (op) && meta_grab_op_is_moving (op)) + { + if (display->compositor) + { + meta_compositor_begin_move (display->compositor, + window, &window->rect, + root_x, root_y); + } + } + meta_topic (META_DEBUG_WINDOW_OPS, "Doing grab op %u on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n", op, window ? window->desc : "none", button, pointer_already_grabbed, @@ -3635,6 +3645,15 @@ meta_display_end_grab_op (MetaDisplay *display, meta_window_calc_showing (display->grab_window); } + if (display->compositor && + display->grab_window && + grab_op_is_mouse (display->grab_op) && + meta_grab_op_is_moving (display->grab_op)) + { + meta_compositor_end_move (display->compositor, + display->grab_window); + } + if (display->grab_have_pointer) { meta_topic (META_DEBUG_WINDOW_OPS, diff --git a/src/spring-model.c b/src/spring-model.c new file mode 100644 index 000000000..406a0e4fe --- /dev/null +++ b/src/spring-model.c @@ -0,0 +1,410 @@ +#include "spring-model.h" +#include + +struct XYPair +{ + double x, y; +}; + +#define GRID_WIDTH 4 +#define GRID_HEIGHT 4 + +#define MODEL_MAX_OBJECTS (GRID_WIDTH * GRID_HEIGHT) +#define MODEL_MAX_SPRINGS (MODEL_MAX_OBJECTS * 2) + +#define DEFAULT_SPRING_K 5.0 +#define DEFAULT_FRICTION 1.4 + +struct Spring { + Object *a; + Object *b; + /* Spring position at rest, from a to b: + offset = b.position - a.position + */ + Vector offset; +}; + +struct Object { + Vector force; + + Point position; + Vector velocity; + + double mass; + double theta; + + int immobile; +}; + +struct Model { + int num_objects; + Object objects[MODEL_MAX_OBJECTS]; + + int num_springs; + Spring springs[MODEL_MAX_SPRINGS]; + + Object *anchor_object; + Vector anchor_offset; + + double friction;/* Friction constant */ + double k;/* Spring constant */ + + double last_time; + double steps; +}; + +static void +object_init (Object *object, + double position_x, double position_y, + double velocity_x, double velocity_y, double mass) +{ + object->position.x = position_x; + object->position.y = position_y; + + object->velocity.x = velocity_x; + object->velocity.y = velocity_y; + + object->mass = mass; + + object->force.x = 0; + object->force.y = 0; + + object->immobile = 0; +} + +static void +spring_init (Spring *spring, + Object *object_a, Object *object_b, + double offset_x, double offset_y) +{ + spring->a = object_a; + spring->b = object_b; + spring->offset.x = offset_x; + spring->offset.y = offset_y; +} + +static void +model_add_spring (Model *model, + Object *object_a, Object *object_b, + double offset_x, double offset_y) +{ + Spring *spring; + + g_assert (model->num_springs < MODEL_MAX_SPRINGS); + + spring = &model->springs[model->num_springs]; + model->num_springs++; + + spring_init (spring, object_a, object_b, offset_x, offset_y); +} + +static void +object_apply_force (Object *object, double fx, double fy) +{ + object->force.x += fx; + object->force.y += fy; +} + +/* The model here can be understood as a rigid body of the spring's + * rest shape, centered on the vector between the two object + * positions. This rigid body is then connected by linear-force + * springs to each object. This model does degnerate into a simple + * spring for linear displacements, and does something reasonable for + * rotation. + * + * There are other possibilities for handling the rotation of the + * spring, and it might be interesting to explore something which has + * better length-preserving properties. For example, with the current + * model, an initial 180 degree rotation of the spring results in the + * spring collapsing down to 0 size before expanding back to it's + * natural size again. + */ + +static void +spring_exert_forces (Spring *spring, double k) +{ + Vector da, db; + Vector a, b; + + a = spring->a->position; + b = spring->b->position; + + /* A nice vector diagram would likely help here, but my ASCII-art + * skills aren't up to the task. Here's how to make your own + * diagram: + * + * Draw a and b, and the vector AB from a to b + * Find the center of AB + * Draw spring->offset so that its center point is on the center of AB + * Draw da from a to the initial point of spring->offset + * Draw db from b to the final point of spring->offset + * + * The math below should be easy to verify from the diagram. + */ + + da.x = 0.5 * (b.x - a.x - spring->offset.x); + da.y = 0.5 * (b.y - a.y - spring->offset.y); + + db.x = 0.5 * (a.x - b.x + spring->offset.x); + db.y = 0.5 * (a.y - b.y + spring->offset.y); + + object_apply_force (spring->a, k * da.x, k * da.y); + object_apply_force (spring->b, k * db.x, k * db.y); +} + +static void +model_step_object (Model *model, Object *object) +{ + Vector acceleration; + + object->theta += 0.05; + + /* Slow down due to friction. */ + object->force.x -= model->friction * object->velocity.x; + object->force.y -= model->friction * object->velocity.y; + + acceleration.x = object->force.x / object->mass; + acceleration.y = object->force.y / object->mass; + + if (object->immobile) + { + object->velocity.x = 0; + object->velocity.y = 0; + } + else + { + object->velocity.x += acceleration.x; + object->velocity.y += acceleration.y; + + object->position.x += object->velocity.x; + object->position.y += object->velocity.y; + } + + object->force.x = 0.0; + object->force.y = 0.0; +} + +static void +model_init_grid (Model *model, MetaRectangle *rect, gboolean expand) +{ + int x, y, i, v_x, v_y; + int hpad, vpad; + + model->num_objects = MODEL_MAX_OBJECTS; + + model->num_springs = 0; + + i = 0; + if (expand) + { + hpad = rect->width / 3; + vpad = rect->height / 3; + } + else + { + hpad = rect->width / 6; + vpad = rect->height / 6; + } + + for (y = 0; y < GRID_HEIGHT; y++) + for (x = 0; x < GRID_WIDTH; x++) + { +#if 0 + v_x = 40 * g_random_double() - 20; + v_y = 40 * g_random_double() - 20; +#endif + v_x = v_y = 0; + +#if 0 + if (expand) + object_init (&model->objects[i], + rect->x + x * rect->width / 6 + rect->width / 4, + rect->y + y * rect->height / 6 + rect->height / 4, + v_x, v_y, 20); + else +#endif + { +#if 0 + g_print ("obj: %d %d\n", rect->x + x * rect->width / 3, + rect->y + y * rect->height / 3); +#endif + object_init (&model->objects[i], + rect->x + x * rect->width / 3, + rect->y + y * rect->height / 3, + v_x, v_y, 15); + } + + if (x > 0) + model_add_spring (model, + &model->objects[i - 1], + &model->objects[i], + hpad, 0); + + if (y > 0) + model_add_spring (model, + &model->objects[i - GRID_WIDTH], + &model->objects[i], + 0, vpad); + + i++; + } +} + +static void +model_init (Model *model, MetaRectangle *rect, gboolean expand) +{ + model->anchor_object = NULL; + + model->k = DEFAULT_SPRING_K; + model->friction = DEFAULT_FRICTION; + + model_init_grid (model, rect, expand); + model->steps = 0; + model->last_time = 0; +} + +Model * +model_new (MetaRectangle *rect, gboolean expand) +{ + Model *model = g_new0 (Model, 1); + + model_init (model, rect, expand); + + return model; +} + +static double +object_distance (Object *object, double x, double y) +{ + double dx, dy; + + dx = object->position.x - x; + dy = object->position.y - y; + + return sqrt (dx*dx + dy*dy); +} + +static Object * +model_find_nearest (Model *model, double x, double y) +{ + Object *object = &model->objects[0]; + double distance, min_distance = 0.0; + int i; + + for (i = 0; i < model->num_objects; i++) { + distance = object_distance (&model->objects[i], x, y); + if (i == 0 || distance < min_distance) { + min_distance = distance; + object = &model->objects[i]; + } + } + + return object; +} + +void +model_begin_move (Model *model, int x, int y) +{ + if (model->anchor_object) + model->anchor_object->immobile = 0; + + model->anchor_object = model_find_nearest (model, x, y); + + model->anchor_offset.x = x - model->anchor_object->position.x; + model->anchor_offset.y = y - model->anchor_object->position.y; + + g_print ("ypos: %f %f\n", model->anchor_object->position.y, + model->anchor_object->position.x); + + g_print ("anchor offset: %f %f\n", + model->anchor_offset.x, + model->anchor_offset.y); + + model->anchor_object->immobile = 1; +} + +void +model_set_anchor (Model *model, + int x, + int y) +{ + if (model->anchor_object) + model->anchor_object->immobile = 0; + + model->anchor_object = model_find_nearest (model, x, y); + model->anchor_offset.x = model->anchor_object->position.x - x; + model->anchor_offset.y = model->anchor_object->position.y - y; + + model->anchor_object->immobile = 1; +} + +void +model_update_move (Model *model, int x, int y) +{ + model->anchor_object->position.x = x - model->anchor_offset.x; + model->anchor_object->position.y = y - model->anchor_offset.y; +} + +static void +on_end_move (Model *model) +{ + if (model->anchor_object) + { + model->anchor_object->immobile = 0; + model->anchor_object = NULL; + } +} + +#define EPSILON 0.01 + +gboolean +model_is_calm (Model *model) +{ + int i, j; + gboolean calm = TRUE; + + for (i = 0; i < model->num_objects; i++) + { + if (model->objects[i].velocity.x > EPSILON || + model->objects[i].velocity.y > EPSILON || + model->objects[i].velocity.x < - EPSILON || + model->objects[i].velocity.y < - EPSILON) + { + return FALSE; + } + } + + return TRUE; +} + +void +model_step (Model *model) +{ + int i; + + for (i = 0; i < model->num_springs; i++) + spring_exert_forces (&model->springs[i], model->k); + + for (i = 0; i < model->num_objects; i++) + model_step_object (model, &model->objects[i]); +} + +void +model_destroy (Model *model) +{ + g_free (model); +} + +void +model_get_position (Model *model, + int i, + int j, + double *x, + double *y) +{ + if (x) + *x = model->objects[j * 4 + i].position.x; + + if (y) + *y = model->objects[j * 4 + i].position.y; +} diff --git a/src/spring-model.h b/src/spring-model.h new file mode 100644 index 000000000..b15e61f15 --- /dev/null +++ b/src/spring-model.h @@ -0,0 +1,31 @@ +#include "window.h" + +typedef struct XYPair Point; +typedef struct XYPair Vector; +typedef struct Spring Spring; +typedef struct Object Object; +typedef struct Model Model; + +Model *model_new (MetaRectangle *rectangle, + gboolean expand); +void model_destroy (Model *model); +void +model_get_position (Model *model, + int i, + int j, + double *x, + double *y); +void +model_step (Model *model); +void +model_destroy (Model *model); +gboolean +model_is_calm (Model *model); +void +model_set_anchor (Model *model, + int x, + int y); +void +model_begin_move (Model *model, int x, int y); +void +model_update_move (Model *model, int x, int y); diff --git a/src/window.c b/src/window.c index 8c12bd407..956f2e867 100644 --- a/src/window.c +++ b/src/window.c @@ -39,6 +39,7 @@ #include "resizepopup.h" #include "xprops.h" #include "group.h" +#include "flash.h" #include "window-props.h" #include "constraints.h" #include "compositor.h" @@ -6661,22 +6662,23 @@ update_move (MetaWindow *window, int new_x, new_y; MetaRectangle old; int shake_threshold; + MetaDisplay *display = window->display; - window->display->grab_latest_motion_x = x; - window->display->grab_latest_motion_y = y; + display->grab_latest_motion_x = x; + display->grab_latest_motion_y = y; - dx = x - window->display->grab_anchor_root_x; - dy = y - window->display->grab_anchor_root_y; + dx = x - display->grab_anchor_root_x; + dy = y - display->grab_anchor_root_y; - new_x = window->display->grab_anchor_window_pos.x + dx; - new_y = window->display->grab_anchor_window_pos.y + dy; + new_x = display->grab_anchor_window_pos.x + dx; + new_y = display->grab_anchor_window_pos.y + dy; meta_verbose ("x,y = %d,%d anchor ptr %d,%d anchor pos %d,%d dx,dy %d,%d\n", x, y, - window->display->grab_anchor_root_x, - window->display->grab_anchor_root_y, - window->display->grab_anchor_window_pos.x, - window->display->grab_anchor_window_pos.y, + display->grab_anchor_root_x, + display->grab_anchor_root_y, + display->grab_anchor_window_pos.x, + display->grab_anchor_window_pos.y, dx, dy); /* Don't bother doing anything if no move has been specified. (This @@ -6703,22 +6705,22 @@ update_move (MetaWindow *window, /* move the unmaximized window to the cursor */ prop = - ((double)(x - window->display->grab_initial_window_pos.x)) / - ((double)window->display->grab_initial_window_pos.width); + ((double)(x - display->grab_initial_window_pos.x)) / + ((double)display->grab_initial_window_pos.width); - window->display->grab_initial_window_pos.x = + display->grab_initial_window_pos.x = x - window->saved_rect.width * prop; - window->display->grab_initial_window_pos.y = y; + display->grab_initial_window_pos.y = y; if (window->frame) { - window->display->grab_initial_window_pos.y += window->frame->child_y / 2; + display->grab_initial_window_pos.y += window->frame->child_y / 2; } - window->saved_rect.x = window->display->grab_initial_window_pos.x; - window->saved_rect.y = window->display->grab_initial_window_pos.y; - window->display->grab_anchor_root_x = x; - window->display->grab_anchor_root_y = y; + window->saved_rect.x = display->grab_initial_window_pos.x; + window->saved_rect.y = display->grab_initial_window_pos.y; + display->grab_anchor_root_x = x; + display->grab_anchor_root_y = y; meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | @@ -6766,9 +6768,9 @@ update_move (MetaWindow *window, META_MAXIMIZE_VERTICAL); } - window->display->grab_initial_window_pos = work_area; - window->display->grab_anchor_root_x = x; - window->display->grab_anchor_root_y = y; + display->grab_initial_window_pos = work_area; + display->grab_anchor_root_x = x; + display->grab_anchor_root_y = y; window->shaken_loose = FALSE; meta_window_maximize (window, @@ -6780,8 +6782,8 @@ update_move (MetaWindow *window, } } - if (window->display->grab_wireframe_active) - old = window->display->grab_wireframe_rect; + if (display->grab_wireframe_active) + old = display->grab_wireframe_rect; else { old = window->rect; @@ -6804,10 +6806,19 @@ update_move (MetaWindow *window, snap, FALSE); - if (window->display->grab_wireframe_active) + if (display->compositor) + { + int root_x = new_x - display->grab_anchor_window_pos.x + display->grab_anchor_root_x; + int root_y = new_y - display->grab_anchor_window_pos.y + display->grab_anchor_root_y; + + meta_compositor_update_move (display->compositor, + window, root_x, root_y); + } + + if (display->grab_wireframe_active) meta_window_update_wireframe (window, new_x, new_y, - window->display->grab_wireframe_rect.width, - window->display->grab_wireframe_rect.height); + display->grab_wireframe_rect.width, + display->grab_wireframe_rect.height); else meta_window_move (window, TRUE, new_x, new_y); }