aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox/mb-wm-layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox/mb-wm-layout.c')
-rw-r--r--matchbox/mb-wm-layout.c753
1 files changed, 753 insertions, 0 deletions
diff --git a/matchbox/mb-wm-layout.c b/matchbox/mb-wm-layout.c
new file mode 100644
index 0000000..7e92998
--- /dev/null
+++ b/matchbox/mb-wm-layout.c
@@ -0,0 +1,753 @@
+#include "matchbox.h"
+#include "mb-wm-client-input.h"
+
+static void
+mb_wm_layout_real_update (MBWMLayout * layout);
+static void
+mb_wm_layout_real_layout_panels (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_input (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_free (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_fullscreen (MBWMLayout *layout, MBGeometry * avail_geom);
+
+static void
+mb_wm_layout_class_init (MBWMObjectClass *klass)
+{
+ MBWMLayoutClass * layout_class = MB_WM_LAYOUT_CLASS (klass);
+
+ layout_class->update = mb_wm_layout_real_update;
+ layout_class->layout_panels = mb_wm_layout_real_layout_panels;
+ layout_class->layout_input = mb_wm_layout_real_layout_input;
+ layout_class->layout_free = mb_wm_layout_real_layout_free;
+ layout_class->layout_fullscreen = mb_wm_layout_real_layout_fullscreen;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMLayout";
+#endif
+}
+
+static void
+mb_wm_layout_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_layout_init (MBWMObject *this, va_list vap)
+{
+ MBWMLayout *layout = MB_WM_LAYOUT (this);
+ MBWMObjectProp prop;
+ MBWindowManager *wm = NULL;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ MBWM_ASSERT (wm);
+
+ layout->wm = wm;
+
+ return 1;
+}
+
+int
+mb_wm_layout_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMLayoutClass),
+ sizeof (MBWMLayout),
+ mb_wm_layout_init,
+ mb_wm_layout_destroy,
+ mb_wm_layout_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWMLayout*
+mb_wm_layout_new (MBWindowManager *wm)
+{
+ MBWMLayout *layout;
+
+ layout = MB_WM_LAYOUT (mb_wm_object_new (MB_WM_TYPE_LAYOUT,
+ MBWMObjectPropWm, wm,
+ NULL));
+ return layout;
+}
+
+Bool
+mb_wm_layout_clip_geometry (MBGeometry *geom,
+ MBGeometry *min,
+ int flags)
+{
+ Bool changed = False;
+
+ if (flags & SET_X)
+ if (geom->x < min->x || geom->x > min->x + min->width)
+ {
+ geom->x = min->x;
+ changed = True;
+ }
+
+ if (flags & SET_Y)
+ if (geom->y < min->y || geom->y > min->y + min->height)
+ {
+ geom->y = min->y;
+ changed = True;
+ }
+
+ if (flags & SET_WIDTH)
+ if (geom->x + geom->width > min->x + min->width)
+ {
+ int old_width = geom->width;
+
+ geom->width = min->x + min->width - geom->x;
+
+ /*
+ * if we are about to reduce the width, and are asked also to set the x
+ * coord, see if we can move the window left so it can be bigger.
+ */
+ if ((flags & SET_X) && old_width > geom->width && geom->x > min->x)
+ {
+ int w_diff = old_width - geom->width;
+ int x = geom->x - w_diff;
+ int x_diff;
+
+ if (x < min->x)
+ x = min->x;
+
+ x_diff = geom->x - x;
+
+ geom->x = x;
+ geom->width += x_diff;
+ }
+
+ changed = True;
+ }
+
+ if (flags & SET_HEIGHT)
+ if (geom->y + geom->height > min->y + min->height)
+ {
+ int old_height = geom->height;
+
+ geom->height = min->y + min->height - geom->y;
+
+ /*
+ * if we are about to reduce the height, and are asked also to set the
+ * y coord, see if we can move the window up so it can be bigger.
+ */
+ if ((flags & SET_Y) && old_height > geom->height && geom->y > min->y)
+ {
+ int h_diff = old_height - geom->height;
+ int y = geom->y - h_diff;
+ int y_diff;
+
+ if (y < min->y)
+ y = min->y;
+
+ y_diff = geom->y - y;
+
+ geom->y = y;
+ geom->height += y_diff;
+ }
+ changed = True;
+ }
+
+ return changed;
+}
+
+Bool
+mb_wm_layout_maximise_geometry (MBGeometry *geom,
+ MBGeometry *max,
+ int flags)
+{
+ Bool changed = False;
+
+ if (flags & SET_X && geom->x != max->x)
+ {
+ geom->x = max->x;
+ changed = True;
+ }
+
+ if (flags & SET_Y && geom->y != max->y)
+ {
+ geom->y = max->y;
+ changed = True;
+ }
+
+ if (flags & SET_WIDTH && geom->width != max->width)
+ {
+ geom->width = max->width;
+ changed = True;
+ }
+
+ if (flags & SET_HEIGHT && geom->height != max->height)
+ {
+ geom->height = max->height;
+ changed = True;
+ }
+
+ return changed;
+}
+
+static void
+mb_wm_layout_real_layout_panels (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+
+ /* FIXME: need to enumerate by *age* in case multiple panels ? */
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeNorth) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int flags = SET_Y;
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedX))
+ flags |= SET_X | SET_WIDTH;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom, flags);
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ /* FIXME: what if this returns False ? */
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ {
+ avail_geom->y = coverage.y + coverage.height;
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeSouth) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int y;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedX))
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X | SET_WIDTH);
+ else
+ need_change = False;
+
+ y = avail_geom->y + avail_geom->height - coverage.height;
+
+ if (y != coverage.y)
+ {
+ coverage.y = y;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeWest) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int flags = SET_X;
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedY))
+ flags |= SET_Y | SET_HEIGHT;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ flags);
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ {
+ avail_geom->x = coverage.x + coverage.width;
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeEast) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int x;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedY))
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_Y|SET_HEIGHT);
+ else
+ need_change = False;
+
+ x = avail_geom->x + avail_geom->width - coverage.width;
+
+ if (x != coverage.x)
+ {
+ coverage.x = x;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+}
+
+static void
+mb_wm_layout_real_layout_input (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveNorth|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_Y|SET_WIDTH);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.width != wm->xdpy_width)
+ {
+ coverage.width = wm->xdpy_width;
+ coverage.x = 0;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ /* FIXME: what if this returns False ? */
+
+ avail_geom->y = coverage.y + coverage.height;
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveSouth|LayoutPrefVisible))
+ {
+ int y;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* First of all, tweak the y value so that we start with position
+ * that as much as possible respects the request for south edge
+ * for the current geometry. For example, the hildon input method
+ * initially maps with height 1 and y 399; it then requests resize
+ * to some sensible height, but does not adjust the y value.
+ */
+ y = avail_geom->y + avail_geom->height - coverage.height;
+
+ if (y < 0)
+ y = 0;
+
+ if (y != coverage.y)
+ need_change = True;
+
+ coverage.y = y;
+
+ /* set x and width */
+ need_change |= mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_WIDTH);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.width != wm->xdpy_width)
+ {
+ coverage.width = wm->xdpy_width;
+ coverage.x = 0;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (coverage.y != avail_geom->y + avail_geom->height - coverage.height)
+ {
+ coverage.y = avail_geom->y + avail_geom->height - coverage.height;
+ need_change = True;
+ }
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveWest|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_Y|SET_HEIGHT);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.height != wm->xdpy_height)
+ {
+ coverage.height = wm->xdpy_height;
+ coverage.y = 0;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ avail_geom->x = coverage.x + coverage.width;
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveEast|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_Y|SET_HEIGHT);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.height != wm->xdpy_height)
+ {
+ coverage.height = wm->xdpy_height;
+ coverage.y = 0;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (coverage.x != avail_geom->x + avail_geom->width - coverage.width)
+ {
+ coverage.x = avail_geom->x + avail_geom->width - coverage.width;
+ need_change = True;
+ }
+
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+}
+
+static void
+mb_wm_layout_real_layout_free (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+ int min_x, max_x, min_y, max_y;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefGrowToFreeSpace|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ if (coverage.x != avail_geom->x
+ || coverage.width != avail_geom->width
+ || coverage.y != avail_geom->y
+ || coverage.height != avail_geom->height)
+ {
+ MBWM_DBG("available geom for free space: %i+%i %ix%i",
+ min_x, min_y, max_x - min_x, max_y - min_y);
+
+ coverage.width = avail_geom->width;
+ coverage.height = avail_geom->height;
+ coverage.x = avail_geom->x;
+ coverage.y = avail_geom->y;
+
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ {
+ MBWMClientLayoutHints hints = mb_wm_client_get_layout_hints (client);
+
+ if ((hints & LayoutPrefPositionFree) && (hints & LayoutPrefVisible) &&
+ !(hints & (LayoutPrefFixedX|LayoutPrefFixedY)))
+ {
+ /* Clip if needed */
+ mb_wm_client_get_coverage (client, &coverage);
+
+ need_change = mb_wm_layout_clip_geometry (&coverage,
+ avail_geom,
+ SET_X | SET_Y |
+ SET_HEIGHT | SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+ }
+
+}
+
+static void
+mb_wm_layout_real_layout_fullscreen (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefFullscreen|LayoutPrefVisible))
+ {
+ MBWMList *l = mb_wm_client_get_transients (client);
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* See if this client comes with an input method and if so,
+ * adjust the available geometry accordingly
+ */
+ while (l)
+ {
+ MBWindowManagerClient * c = l->data;
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (c) == MBWMClientTypeInput)
+ {
+ MBGeometry geom;
+ mb_wm_client_get_coverage (c, &geom);
+
+ if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveSouth|LayoutPrefVisible))
+ {
+ if (geom.y < avail_geom->y + avail_geom->height)
+ {
+ avail_geom->height = geom.y - avail_geom->y;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveNorth|LayoutPrefVisible))
+ {
+ if (geom.height && geom.height + geom.y > avail_geom->y)
+ {
+ int y = avail_geom->y;
+
+ avail_geom->y = geom.y + geom.height;
+ avail_geom->height -= y - avail_geom->y;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveWest|LayoutPrefVisible))
+ {
+ if (geom.x < avail_geom->x + avail_geom->width)
+ {
+ avail_geom->width = geom.x - avail_geom->x;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveEast|LayoutPrefVisible))
+ {
+ if (geom.width && geom.width + geom.x > avail_geom->x)
+ {
+ int x = avail_geom->x;
+
+ avail_geom->x = geom.x + geom.width;
+ avail_geom->width -= x - avail_geom->x;
+ }
+ }
+
+ break;
+ }
+
+ l = l->next;
+ }
+
+ if (coverage.x != avail_geom->x
+ || coverage.width != avail_geom->width
+ || coverage.y != avail_geom->y
+ || coverage.height != avail_geom->height)
+ {
+ coverage.width = avail_geom->width;
+ coverage.height = avail_geom->height;
+ coverage.x = avail_geom->x;
+ coverage.y = avail_geom->y;
+
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+
+ mb_wm_util_list_free (l);
+ }
+}
+
+static void
+mb_wm_layout_real_update (MBWMLayout * layout)
+{
+ MBWMLayoutClass *klass;
+ MBWindowManager *wm = layout->wm;
+ MBGeometry avail_geom;
+
+ klass = MB_WM_LAYOUT_CLASS (MB_WM_OBJECT_GET_CLASS (layout));
+
+ MBWM_ASSERT (klass->layout_panels);
+ MBWM_ASSERT (klass->layout_input);
+ MBWM_ASSERT (klass->layout_free);
+ MBWM_ASSERT (klass->layout_fullscreen);
+
+ mb_wm_get_display_geometry (wm, &avail_geom);
+
+ /*
+ cycle through clients, laying out each in below order.
+ Note they must have LayoutPrefVisible set.
+
+ LayoutPrefReserveEdgeNorth
+ LayoutPrefReserveEdgeSouth
+
+ LayoutPrefReserveEdgeEast
+ LayoutPrefReserveEdgeWest
+
+ LayoutPrefReserveNorth
+ LayoutPrefReserveSouth
+
+ LayoutPrefReserveEast
+ LayoutPrefReserveWest
+
+ LayoutPrefGrowToFreeSpace
+
+ LayoutPrefFullscreen
+
+ XXX need to check they are mapped too
+
+ foreach client with LayoutPrefReserveEdgeNorth & LayoutPrefVisible
+ grab there current geometry
+ does it fit well into current restraints ( min_, max_ )
+ yes leave
+ no resize so it does, mark dirty
+ set min_x, max_y, min_y, max_y to current size
+ repeat for next condition
+
+ mb_wm_client_get_coverage (MBWindowManagerClient *client,
+ MBGeometry *coverage)
+
+ */
+
+ klass->layout_panels (layout, &avail_geom);
+ klass->layout_input (layout, &avail_geom);
+ klass->layout_free (layout, &avail_geom);
+
+ mb_wm_get_display_geometry (wm, &avail_geom);
+ klass->layout_fullscreen (layout, &avail_geom);
+}
+
+void
+mb_wm_layout_update (MBWMLayout * layout)
+{
+ MBWMLayoutClass *klass;
+
+ klass = MB_WM_LAYOUT_CLASS (MB_WM_OBJECT_GET_CLASS (layout));
+
+ MBWM_ASSERT (klass->update);
+
+ klass->update (layout);
+}