@@ -1,4 +1,4 @@

#include "hd-atoms.h"
#include "hd-util.h"

#include <matchbox/core/mb-wm.h>
@@ -17,6 +17,11 @@

#include <gdk/gdk.h>

/* whether our display width < height, not accounting for any rotation */
static int display_is_portrait = -1;

static int initially_rotated = -1;

void *
hd_util_get_win_prop_data_and_validate (Display *xdpy,
Window xwin,
@@ -230,7 +235,6 @@ static RRCrtc
get_primary_crtc (MBWindowManager *wm, XRRScreenResources *res)
{
int i;
RROutput primary;
XRROutputInfo *output;
RRCrtc ret = ~0UL;
Atom rr_connector_type, rr_connector_panel;
@@ -242,10 +246,10 @@ get_primary_crtc (MBWindowManager *wm, XRRScreenResources *res)
if (res->ncrtc == 1)
return res->crtcs[0];

rr_connector_type = hd_comp_mgr_get_atom (HD_COMP_MGR (wm->comp_mgr),
HD_ATOM_RANDR_CONNECTOR_TYPE);
rr_connector_panel = hd_comp_mgr_get_atom (HD_COMP_MGR (wm->comp_mgr),
HD_ATOM_RANDR_CONNECTOR_TYPE_PANEL);
rr_connector_type = hd_comp_mgr_wm_get_atom(
wm, HD_ATOM_RANDR_CONNECTOR_TYPE);
rr_connector_panel = hd_comp_mgr_wm_get_atom(
wm, HD_ATOM_RANDR_CONNECTOR_TYPE_PANEL);

for (i = 0; i < res->noutput; i++)
{
@@ -271,12 +275,13 @@ get_primary_crtc (MBWindowManager *wm, XRRScreenResources *res)

if (ret == ~0UL)
{
primary = XRRGetOutputPrimary (wm->xdpy, wm->root_win->xwindow);
RROutput primary = XRRGetOutputPrimary (wm->xdpy, wm->root_win->xwindow);

if (primary == None)
return ret;

output = XRRGetOutputInfo (wm->xdpy, res, primary);

if (output)
{
ret = output->crtc;
@@ -314,38 +319,47 @@ void hd_util_set_screen_size_property(MBWindowManager *wm,
(unsigned char *)value, 2);
}

/* Change the screen's orientation by rotating 90 degrees
* (portrait mode) or going back to landscape.
* Returns whether the orientation has actually changed. */
gboolean
hd_util_change_screen_orientation (MBWindowManager *wm,
gboolean goto_portrait)
static gboolean
randr_supported(MBWindowManager *wm)
{
int rr_major, rr_minor;
static RRCrtc crtc = ~0UL; /* cache to avoid potentially lots of roundtrips */
static int randr_supported = -1;
XRRScreenResources *res;
XRRCrtcInfo *crtc_info;
Rotation want;
Status ret;
int width, height, width_mm, height_mm;
unsigned long one = 1;
int rr_major, rr_minor;

if (randr_supported == -1)
{
ret = XRRQueryVersion (wm->xdpy, &rr_major, &rr_minor);
if (ret == True && (rr_major > 1 || (rr_major == 1 && rr_minor >= 3)))
Status ok = XRRQueryVersion (wm->xdpy, &rr_major, &rr_minor);

if (ok == 1 && (rr_major > 1 || (rr_major == 1 && rr_minor >= 3)))
randr_supported = 1;
else
randr_supported = 0;
}
if (!randr_supported)

return randr_supported != 0;
}

static gboolean
hd_util_change_screen_orientation_real (MBWindowManager *wm,
gboolean goto_portrait,
gboolean do_change)
{
static RRCrtc crtc = ~0UL; /* cache to avoid potentially lots of roundtrips */
XRRScreenResources *res;
XRRCrtcInfo *crtc_info;
Rotation want;
Status status = RRSetConfigSuccess;
int width, height, width_mm, height_mm;
unsigned long one = 1;
gboolean rv = FALSE;

if (!randr_supported(wm))
{
g_debug ("Server does not support RandR 1.3\n");
return FALSE;
}

res = XRRGetScreenResources (wm->xdpy, wm->root_win->xwindow);

if (!res)
{
g_warning ("Couldn't get RandR screen resources\n");
@@ -354,102 +368,159 @@ hd_util_change_screen_orientation (MBWindowManager *wm,

if (crtc == ~0UL)
crtc = get_primary_crtc (wm, res);

if (crtc == ~0UL)
{
g_warning ("Couldn't find CRTC to rotate\n");
return FALSE;
goto err_res;
}

crtc_info = XRRGetCrtcInfo (wm->xdpy, res, crtc);

if (!crtc_info)
{
g_warning ("Couldn't find CRTC info\n");
return FALSE;
goto err_res;
}

if (display_is_portrait == -1)
display_is_portrait = FALSE;

if (goto_portrait)
{
g_debug ("Entering portrait mode");
want = RR_Rotate_90;
width = MIN(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
height = MAX(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
width_mm = MIN(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
height_mm = MAX(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
if (do_change)
{
g_debug ("Entering portrait mode");
want = RR_Rotate_90;
width = MIN(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
height = MAX(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
width_mm = MIN(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
height_mm = MAX(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
}

if ((crtc_info->rotation == RR_Rotate_0 &&
crtc_info->width < crtc_info->height) ||
(crtc_info->rotation == RR_Rotate_270 &&
crtc_info->width > crtc_info->height))
{
want = RR_Rotate_0;
display_is_portrait = TRUE;
}
}
else
{
g_debug ("Leaving portrait mode");
want = RR_Rotate_0;
width = MAX(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
height = MIN(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
width_mm = MAX(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
height_mm = MIN(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
}

if (!(crtc_info->rotations & want))
{
g_warning ("CRTC does not support rotation (0x%.8X vs. 0x%.8X)",
crtc_info->rotations, want);
return FALSE;
if (do_change)
{
g_debug ("Leaving portrait mode");
want = RR_Rotate_0;
width = MAX(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
height = MIN(DisplayWidth (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeight (wm->xdpy, DefaultScreen (wm->xdpy)));
width_mm = MAX(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
height_mm = MIN(DisplayWidthMM (wm->xdpy, DefaultScreen (wm->xdpy)),
DisplayHeightMM (wm->xdpy, DefaultScreen (wm->xdpy)));
}

if ((crtc_info->rotation == RR_Rotate_0 &&
crtc_info->width < crtc_info->height) ||
(crtc_info->rotation == RR_Rotate_270 &&
crtc_info->width > crtc_info->height))
{
want = RR_Rotate_270;
display_is_portrait = TRUE;
}
}

if (crtc_info->rotation == want)
if (initially_rotated == -1)
{
g_debug ("Requested rotation already active");
return FALSE;
initially_rotated = crtc_info->rotation != RR_Rotate_0 &&
crtc_info->rotation != RR_Rotate_180;
}

/* We must call glFinish here in order to be sure that OpenGL won't be
* trying to render stuff while we do the transition - as this sometimes
* causes rubbish to be displayed. */
glFinish();
if (do_change)
{
if (!(crtc_info->rotations & want))
{
g_warning ("CRTC does not support rotation (0x%.8X vs. 0x%.8X)",
crtc_info->rotations, want);
goto err_crtc_info;
}

/* Grab the server around rotation to prevent clients attempting to
* draw at inopportune times. */
XGrabServer (wm->xdpy);
/* Stop windows being reconfigured */
XChangeProperty(wm->xdpy, wm->root_win->xwindow,
wm->atoms[MBWM_ATOM_MAEMO_SUPPRESS_ROOT_RECONFIGURATION],
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)&one, 1);

/* Disable the CRTC first, as it doesn't fit within our existing screen. */
XRRSetCrtcConfig (wm->xdpy, res, crtc, crtc_info->timestamp, 0, 0, None,
RR_Rotate_0, NULL, 0);
/* Then change the screen size to accommodate our glorious new CRTC. */
XRRSetScreenSize (wm->xdpy, wm->root_win->xwindow, width, height,
width_mm, height_mm);
/* And now rotate. */
ret = XRRSetCrtcConfig (wm->xdpy, res, crtc, crtc_info->timestamp,
crtc_info->x, crtc_info->y, crtc_info->mode, want,
crtc_info->outputs, crtc_info->noutput);

/* hd_util_root_window_configured will be called directly after this root
* window has been reconfigured */

/* Allow clients to redraw. */
XUngrabServer (wm->xdpy);
XFlush (wm->xdpy); /* <-- this is required to avoid a lock-up */
if (crtc_info->rotation == want)
{
g_debug ("Requested rotation already active");
goto err_crtc_info;
}

/* We must call glFinish here in order to be sure that OpenGL won't be
* trying to render stuff while we do the transition - as this sometimes
* causes rubbish to be displayed. */
glFinish();

/* Grab the server around rotation to prevent clients attempting to
* draw at inopportune times. */
XGrabServer (wm->xdpy);
/* Stop windows being reconfigured */
XChangeProperty(wm->xdpy, wm->root_win->xwindow,
wm->atoms[MBWM_ATOM_MAEMO_SUPPRESS_ROOT_RECONFIGURATION],
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)&one, 1);

/* Disable the CRTC first, as it doesn't fit within our existing screen. */
XRRSetCrtcConfig (wm->xdpy, res, crtc, crtc_info->timestamp, 0, 0, None,
RR_Rotate_0, NULL, 0);
/* Then change the screen size to accommodate our glorious new CRTC. */
XRRSetScreenSize (wm->xdpy, wm->root_win->xwindow, width, height,
width_mm, height_mm);
/* And now rotate. */
status = XRRSetCrtcConfig (wm->xdpy, res, crtc, crtc_info->timestamp,
crtc_info->x, crtc_info->y, crtc_info->mode, want,
crtc_info->outputs, crtc_info->noutput);

/* hd_util_root_window_configured will be called directly after this root
* window has been reconfigured */

/* Allow clients to redraw. */
XUngrabServer (wm->xdpy);
XFlush (wm->xdpy); /* <-- this is required to avoid a lock-up */
}

rv = TRUE;

err_crtc_info:
XRRFreeCrtcInfo (crtc_info);

err_res:
XRRFreeScreenResources (res);

if (ret != Success)
if (rv == TRUE && do_change)
{
g_warning ("XRRSetCrtcConfig() failed: %d", ret);
return FALSE;
if (status != RRSetConfigSuccess)
{
g_warning ("XRRSetCrtcConfig() failed: %d", status);
return FALSE;
}

hd_render_manager_flip_input_viewport();
}

hd_render_manager_flip_input_viewport();
return rv;
}

return TRUE;
/* Change the screen's orientation by rotating 90 degrees
* (portrait mode) or going back to landscape.
* Returns whether the orientation has actually changed. */
gboolean
hd_util_change_screen_orientation (MBWindowManager *wm,
gboolean goto_portrait)
{
return hd_util_change_screen_orientation_real(wm, goto_portrait, TRUE);
}

/* This is the finishing counterpart of hd_util_change_screen_orientation(),
@@ -811,3 +882,58 @@ float hd_key_frame_interpolate(HdKeyFrameList *k, float x)
}
return k->keyframes[idx]*(1-n) + k->keyframes[idx+1]*n;
}

void
hd_util_display_portraitness_init(MBWindowManager *wm)
{
g_assert(display_is_portrait == -1);
hd_util_change_screen_orientation_real(wm, FALSE, FALSE);
}

/* Display width, accounting for initial rotation */
guint
hd_util_display_width()
{
static guint width = 0;

if (width == 0)
{
if ((!display_is_portrait && !initially_rotated) ||
(display_is_portrait && initially_rotated))
{
width = WidthOfScreen(ScreenOfDisplay(
clutter_x11_get_default_display(), 0));
}
else
{
width = HeightOfScreen(ScreenOfDisplay(
clutter_x11_get_default_display(), 0));
}
}

return width;
}

/* Display height, accounting for initial rotation */
guint
hd_util_display_height()
{
static guint height = 0;

if (height == 0)
{
if ((!display_is_portrait && !initially_rotated) ||
(display_is_portrait && initially_rotated))
{
height = HeightOfScreen(ScreenOfDisplay(
clutter_x11_get_default_display(), 0));
}
else
{
height = WidthOfScreen(ScreenOfDisplay(
clutter_x11_get_default_display(), 0));
}
}

return height;
}
@@ -48,4 +48,12 @@ HdKeyFrameList *hd_key_frame_list_create(const char *keys);
void hd_key_frame_list_free(HdKeyFrameList *k);
float hd_key_frame_interpolate(HdKeyFrameList *k, float x);

void hd_util_display_portraitness_init(MBWindowManager *wm);

/* Display width, accounting for initial rotation */
guint hd_util_display_width(void);

/* Display height, accounting for initial rotation */
guint hd_util_display_height(void);

#endif