[broadway] Add configure event for browser-side geometry changes

Atm this only works for the useToplevelWindows case, but we can add
a browser wm to make use of it inside the browser too.
This commit is contained in:
Alexander Larsson 2011-04-06 16:39:07 +02:00
parent 1365e93fad
commit adc05ae6b7
6 changed files with 166 additions and 24 deletions

View File

@ -88,7 +88,27 @@ function resizeBrowserWindow(window, w, h) {
h + outerH - innerH);
}
function resizeCanvas(canvas, w, h)
{
/* Canvas resize clears the data, so we need to save it first */
var tmpCanvas = canvas.ownerDocument.createElement("canvas");
tmpCanvas.width = canvas.width;
tmpCanvas.height = canvas.height;
var tmpContext = tmpCanvas.getContext("2d");
tmpContext.globalCompositeOperation = "copy";
tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
canvas.width = w;
canvas.height = h;
var context = canvas.getContext("2d");
context.globalCompositeOperation = "copy";
context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
}
var useToplevelWindows = false;
var toplevelWindows = [];
var grab = new Object();
grab.window = null;
grab.ownerEvents = false;
@ -103,6 +123,9 @@ var windowWithMouse = 0;
var surfaces = {};
var outstandingCommands = new Array();
var inputSocket = null;
var frameSizeX = -1;
var frameSizeY = -1;
var GDK_CROSSING_NORMAL = 0;
var GDK_CROSSING_GRAB = 1;
@ -214,6 +237,67 @@ function ensureSurfaceInDocument(surface, doc)
}
}
var windowGeometryTimeout = null;
function updateBrowserWindowGeometry(win) {
if (win.closed)
return;
var surface = win.surface;
var innerW = win.innerWidth;
var innerH = win.innerHeight;
var x = surface.x;
var y = surface.y;
if (frameSizeX > 0) {
x = win.screenX + frameSizeX;
y = win.screenY + frameSizeY;
}
if (x != surface.x || y != surface.y ||
innerW != surface.width || innerH != surface.height) {
var oldX = surface.x;
var oldY = surface.y;
surface.x = x;
surface.y = y;
if (surface.width != innerW || surface.height != innerH)
resizeCanvas(surface.canvas, innerW, innerH);
surface.width = innerW;
surface.height = innerH;
sendInput ("w", [surface.id, surface.x, surface.y, surface.width, surface.height]);
for (id in surfaces) {
if (surfaces[id].transientToplevel != null && surfaces[id].transientToplevel == surface) {
var childSurface = surfaces[id];
childSurface.x += surface.x - oldX;
childSurface.y += surface.y - oldY;
sendInput ("w", [childSurface.id, childSurface.x, childSurface.y, childSurface.width, childSurface.height]);
}
}
}
}
function registerWindow(win)
{
toplevelWindows.push(win);
win.onresize = function(ev) { updateBrowserWindowGeometry(ev.target); };
if (!windowGeometryTimeout)
windowGeometryTimeout = setInterval(function () { toplevelWindows.forEach(updateBrowserWindowGeometry); }, 2000);
}
function unregisterWindow(win)
{
var i = toplevelWindows.indexOf(win);
if (i >= 0)
toplevelWindows.splice(i, 1);
if (windowGeometryTimeout && toplevelWindows.length == 0) {
clearInterval(windowGeometryTimeout);
windowGeometryTimeout = null;
}
}
function getTransientToplevel(surface)
{
while (surface.transientParent != 0) {
@ -232,6 +316,7 @@ function cmdCreateSurface(id, x, y, width, height, isTemp)
surface.visible = false;
surface.window = null;
surface.document = document;
surface.transientToplevel = null;
var canvas = document.createElement("canvas");
canvas.width = width;
@ -269,6 +354,8 @@ function cmdShowSurface(id)
'width='+surface.width+',height='+surface.height+
',left='+surface.x+',top='+surface.y+',screenX='+surface.x+',screenY='+surface.y+
',location=no,menubar=no,scrollbars=no,toolbar=no');
win.surface = surface;
registerWindow(win);
doc = win.document;
doc.open();
doc.write("<body></body>");
@ -278,11 +365,11 @@ function cmdShowSurface(id)
xOffset = 0;
yOffset = 0;
} else {
var transientToplevel = getTransientToplevel(surface);
if (transientToplevel) {
doc = transientToplevel.window.document;
xOffset = surface.x - transientToplevel.x;
yOffset = surface.y - transientToplevel.y;
surface.transientToplevel = getTransientToplevel(surface);
if (surface.transientToplevel) {
doc = surface.transientToplevel.window.document;
xOffset = surface.x - surface.transientToplevel.x;
yOffset = surface.y - surface.transientToplevel.y;
}
}
@ -303,12 +390,13 @@ function cmdHideSurface(id)
return;
surface.visible = false;
surfaces[id].canvas.style["display"] = "none";
surface.canvas.style["display"] = "none";
// Import the canvas into the main document
ensureSurfaceInDocument(surface, document);
if (surface.window) {
unregisterWindow(surface.window);
surface.window.close();
surface.window = null;
}
@ -346,7 +434,7 @@ function cmdMoveSurface(id, x, y)
* However this isn't *strictly* invalid, as any WM could have done whatever it
* wanted with the positioning of the window.
*/
surface.window.moveTo(surface.x, surface.y);
//surface.window.moveTo(surface.x, surface.y);
} else {
var xOffset = surface.x;
var yOffset = surface.y;
@ -373,19 +461,7 @@ function cmdResizeSurface(id, w, h)
/* Flush any outstanding draw ops before changing size */
flushSurface(surface);
/* Canvas resize clears the data, so we need to save it first */
var tmpCanvas = surface.document.createElement("canvas");
tmpCanvas.width = surface.canvas.width;
tmpCanvas.height = surface.canvas.height;
var tmpContext = tmpCanvas.getContext("2d");
tmpContext.globalCompositeOperation = "copy";
tmpContext.drawImage(surface.canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
surface.canvas.width = w;
surface.canvas.height = h;
surface.context.globalCompositeOperation = "copy";
surface.context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
resizeCanvas(surface.canvas, w, h);
if (surface.window) {
resizeBrowserWindow(surface.window, w, h);
@ -649,6 +725,19 @@ function getEffectiveEventTarget (id) {
function updateForEvent(ev) {
lastTimeStamp = ev.timeStamp;
if (ev.target.surface && ev.target.surface.window) {
var win = ev.target.surface.window;
if (ev.screenX != undefined && ev.clientX != undefined) {
var newFrameSizeX = ev.screenX - ev.clientX - win.screenX;
var newFrameSizeY = ev.screenY - ev.clientY - win.screenY;
if (newFrameSizeX != frameSizeX || newFrameSizeY != frameSizeY) {
frameSizeX = newFrameSizeX;
frameSizeY = newFrameSizeY;
toplevelWindows.forEach(updateBrowserWindowGeometry);
}
}
updateBrowserWindowGeometry(win);
}
}
function onMouseMove (ev) {
@ -839,4 +928,8 @@ function connect()
alert("WebSocket not supported, input will not work!");
}
setupDocument(document);
window.onunload = function (ev) {
for (var i = 0; i < toplevelWindows.length; i++)
toplevelWindows[i].close();
};
}

View File

@ -248,6 +248,19 @@ parse_input_message (BroadwayInput *input, const char *message)
msg.grab_reply.res = strtol(p, &p, 10);
break;
case 'w':
msg.configure_notify.id = strtol(p, &p, 10);
p++; /* Skip , */
msg.configure_notify.x = strtol (p, &p, 10);
p++; /* Skip , */
msg.configure_notify.y = strtol (p, &p, 10);
p++; /* Skip , */
msg.configure_notify.width = strtol (p, &p, 10);
p++; /* Skip , */
msg.configure_notify.height = strtol (p, &p, 10);
p++; /* Skip , */
break;
default:
g_printerr ("Unknown input command %s\n", message);
break;

View File

@ -87,6 +87,15 @@ typedef struct {
int res;
} BroadwayInputGrabReply;
typedef struct {
BroadwayInputBaseMsg base;
int id;
int x;
int y;
int width;
int height;
} BroadwayInputConfigureNotify;
typedef union {
BroadwayInputBaseMsg base;
BroadwayInputPointerMsg pointer;
@ -95,6 +104,7 @@ typedef union {
BroadwayInputScrollMsg scroll;
BroadwayInputKeyMsg key;
BroadwayInputGrabReply grab_reply;
BroadwayInputConfigureNotify configure_notify;
} BroadwayInputMsg;
struct _GdkBroadwayDisplay

View File

@ -270,6 +270,30 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
case 'u':
_gdk_display_device_grab_update (display, display->core_pointer, NULL, message->base.serial);
break;
case 'w':
window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->configure_notify.id));
if (window)
{
window->x = message->configure_notify.x;
window->y = message->configure_notify.y;
window->width = message->configure_notify.width;
window->height = message->configure_notify.height;
_gdk_window_update_size (window);
_gdk_broadway_window_resize_surface (window);
event = gdk_event_new (GDK_CONFIGURE);
event->configure.window = g_object_ref (window);
event->configure.x = message->configure_notify.x;
event->configure.y = message->configure_notify.y;
event->configure.width = message->configure_notify.width;
event->configure.height = message->configure_notify.height;
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event, message->base.serial);
}
break;
default:
g_printerr ("Unknown input command %c\n", message->base.type);
break;

View File

@ -207,6 +207,7 @@ gboolean _gdk_broadway_window_simulate_button (GdkWindow *window,
guint button,
GdkModifierType modifiers,
GdkEventType button_pressrelease);
void _gdk_broadway_window_resize_surface (GdkWindow *window);
void _gdk_broadway_cursor_update_theme (GdkCursor *cursor);
void _gdk_broadway_cursor_display_finalize (GdkDisplay *display);

View File

@ -368,8 +368,8 @@ _gdk_broadway_display_create_window_impl (GdkDisplay *display,
window->window_type == GDK_WINDOW_TEMP);
}
static void
resize_surface (GdkWindow *window)
void
_gdk_broadway_window_resize_surface (GdkWindow *window)
{
GdkWindowImplBroadway *impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
cairo_surface_t *old, *last_old;
@ -396,6 +396,8 @@ resize_surface (GdkWindow *window)
NULL, NULL);
impl->ref_surface = NULL;
}
gdk_window_invalidate_rect (window, NULL, TRUE);
}
static void
@ -641,8 +643,7 @@ gdk_window_broadway_move_resize (GdkWindow *window,
window->width = width;
window->height = height;
resize_surface (window);
gdk_window_invalidate_rect (window, NULL, TRUE);
_gdk_broadway_window_resize_surface (window);
}
}