2013-06-13 15:58:53 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_MMAN_H
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <sys/mman.h>
|
2013-06-13 15:58:53 +00:00
|
|
|
#endif
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include "gdkbroadway-server.h"
|
|
|
|
|
|
|
|
#include "gdkprivate-broadway.h"
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <glib/gprintf.h>
|
2013-06-13 16:15:10 +00:00
|
|
|
#ifdef G_OS_UNIX
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <gio/gunixsocketaddress.h>
|
2013-06-13 16:15:10 +00:00
|
|
|
#endif
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2013-07-01 12:51:03 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <unistd.h>
|
2013-07-01 12:51:03 +00:00
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
#include <io.h>
|
|
|
|
#define ftruncate _chsize_s
|
|
|
|
#endif
|
2012-12-21 23:02:55 +00:00
|
|
|
#include <sys/types.h>
|
2013-06-13 17:35:43 +00:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
2013-06-13 16:55:40 +00:00
|
|
|
#include "gdkintl.h"
|
2012-12-21 23:02:55 +00:00
|
|
|
|
|
|
|
typedef struct BroadwayInput BroadwayInput;
|
|
|
|
|
|
|
|
struct _GdkBroadwayServer {
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
guint32 next_serial;
|
|
|
|
GSocketConnection *connection;
|
|
|
|
|
|
|
|
guint32 recv_buffer_size;
|
|
|
|
guint8 recv_buffer[1024];
|
|
|
|
|
|
|
|
guint process_input_idle;
|
|
|
|
GList *incomming;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GdkBroadwayServerClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean input_available_cb (gpointer stream, gpointer user_data);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GdkBroadwayServer, gdk_broadway_server, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_broadway_server_init (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
server->next_serial = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_broadway_server_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
G_OBJECT_CLASS (gdk_broadway_server_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_broadway_server_class_init (GdkBroadwayServerClass * class)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
|
|
|
|
object_class->finalize = gdk_broadway_server_finalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
_gdk_broadway_server_lookahead_event (GdkBroadwayServer *server,
|
|
|
|
const char *types)
|
|
|
|
{
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gulong
|
|
|
|
_gdk_broadway_server_get_next_serial (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
return (gulong)server->next_serial;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkBroadwayServer *
|
2013-06-13 16:55:40 +00:00
|
|
|
_gdk_broadway_server_new (const char *display, GError **error)
|
2012-12-21 23:02:55 +00:00
|
|
|
{
|
|
|
|
GdkBroadwayServer *server;
|
|
|
|
char *basename;
|
|
|
|
GSocketClient *client;
|
|
|
|
GSocketConnection *connection;
|
2013-06-13 16:55:40 +00:00
|
|
|
GInetAddress *inet;
|
2012-12-21 23:02:55 +00:00
|
|
|
GSocketAddress *address;
|
|
|
|
GPollableInputStream *pollable;
|
|
|
|
GInputStream *in;
|
|
|
|
GSource *source;
|
|
|
|
char *path;
|
2013-06-13 16:55:40 +00:00
|
|
|
char *local_socket_type = NULL;
|
|
|
|
int port;
|
2012-12-21 23:02:55 +00:00
|
|
|
|
2013-06-13 16:55:40 +00:00
|
|
|
if (display == NULL)
|
|
|
|
{
|
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
display = ":0";
|
|
|
|
#else
|
2013-07-01 12:46:25 +00:00
|
|
|
display = ":tcp";
|
2013-06-13 16:55:40 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_str_has_prefix (display, ":tcp"))
|
|
|
|
{
|
|
|
|
port = 9090 + strtol (display + strlen (":tcp"), NULL, 10);
|
|
|
|
|
|
|
|
inet = g_inet_address_new_from_string ("127.0.0.1");
|
|
|
|
address = g_inet_socket_address_new (inet, port);
|
|
|
|
g_object_unref (inet);
|
|
|
|
}
|
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
else if (display[0] == ':' && g_ascii_isdigit(display[1]))
|
|
|
|
{
|
|
|
|
port = strtol (display + strlen (":"), NULL, 10);
|
|
|
|
basename = g_strdup_printf ("broadway%d.socket", port + 1);
|
|
|
|
path = g_build_filename (g_get_user_runtime_dir (), basename, NULL);
|
|
|
|
g_free (basename);
|
|
|
|
|
|
|
|
address = g_unix_socket_address_new_with_type (path, -1,
|
|
|
|
G_UNIX_SOCKET_ADDRESS_ABSTRACT);
|
|
|
|
g_free (path);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
|
|
_("broadway display type not supported '%s'"), display);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-21 23:02:55 +00:00
|
|
|
|
2013-06-13 16:55:40 +00:00
|
|
|
g_free (local_socket_type);
|
2012-12-21 23:02:55 +00:00
|
|
|
|
|
|
|
client = g_socket_client_new ();
|
|
|
|
|
|
|
|
connection = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (address), NULL, error);
|
2013-06-13 16:55:40 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
g_object_unref (address);
|
|
|
|
g_object_unref (client);
|
|
|
|
|
|
|
|
if (connection == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
server = g_object_new (GDK_TYPE_BROADWAY_SERVER, NULL);
|
|
|
|
server->connection = connection;
|
|
|
|
|
|
|
|
in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
|
|
|
|
pollable = G_POLLABLE_INPUT_STREAM (in);
|
|
|
|
|
|
|
|
source = g_pollable_input_stream_create_source (pollable, NULL);
|
|
|
|
g_source_attach (source, NULL);
|
|
|
|
g_source_set_callback (source, (GSourceFunc)input_available_cb, server, NULL);
|
|
|
|
|
|
|
|
return server;
|
|
|
|
}
|
|
|
|
|
|
|
|
guint32
|
|
|
|
_gdk_broadway_server_get_last_seen_time (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static guint32
|
|
|
|
gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayRequestBase *base,
|
|
|
|
gsize size, guint32 type)
|
|
|
|
{
|
|
|
|
GOutputStream *out;
|
|
|
|
gsize written;
|
|
|
|
|
|
|
|
base->size = size;
|
|
|
|
base->type = type;
|
|
|
|
base->serial = server->next_serial++;
|
|
|
|
|
|
|
|
out = g_io_stream_get_output_stream (G_IO_STREAM (server->connection));
|
|
|
|
|
|
|
|
if (!g_output_stream_write_all (out, base, size, &written, NULL, NULL))
|
|
|
|
{
|
|
|
|
g_printerr ("Unable to write to server\n");
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (written == size);
|
|
|
|
|
|
|
|
return base->serial;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define gdk_broadway_server_send_message(_server, _msg, _type) \
|
|
|
|
gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type)
|
|
|
|
|
|
|
|
static void
|
|
|
|
parse_all_input (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
guint8 *p, *end;
|
|
|
|
guint32 size;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
p = server->recv_buffer;
|
|
|
|
end = p + server->recv_buffer_size;
|
|
|
|
|
|
|
|
while (p + sizeof (guint32) <= end)
|
|
|
|
{
|
|
|
|
memcpy (&size, p, sizeof (guint32));
|
|
|
|
if (p + size > end)
|
|
|
|
break;
|
|
|
|
|
|
|
|
reply = g_memdup (p, size);
|
|
|
|
p += size;
|
|
|
|
|
|
|
|
server->incomming = g_list_append (server->incomming, reply);
|
|
|
|
}
|
2013-01-08 16:33:29 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
if (p < end)
|
|
|
|
memmove (server->recv_buffer, p, end - p);
|
|
|
|
server->recv_buffer_size = end - p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
read_some_input_blocking (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
GInputStream *in;
|
|
|
|
gssize res;
|
|
|
|
|
|
|
|
in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
|
|
|
|
|
|
|
|
g_assert (server->recv_buffer_size < sizeof (server->recv_buffer));
|
|
|
|
res = g_input_stream_read (in, &server->recv_buffer[server->recv_buffer_size],
|
|
|
|
sizeof (server->recv_buffer) - server->recv_buffer_size,
|
|
|
|
NULL, NULL);
|
|
|
|
|
|
|
|
if (res <= 0)
|
|
|
|
{
|
|
|
|
g_printerr ("Unable to read from broadway server\n");
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
server->recv_buffer_size += res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
read_some_input_nonblocking (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
GInputStream *in;
|
|
|
|
GPollableInputStream *pollable;
|
|
|
|
gssize res;
|
|
|
|
GError *error;
|
|
|
|
|
|
|
|
in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
|
|
|
|
pollable = G_POLLABLE_INPUT_STREAM (in);
|
|
|
|
|
|
|
|
g_assert (server->recv_buffer_size < sizeof (server->recv_buffer));
|
|
|
|
error = NULL;
|
|
|
|
res = g_pollable_input_stream_read_nonblocking (pollable, &server->recv_buffer[server->recv_buffer_size],
|
|
|
|
sizeof (server->recv_buffer) - server->recv_buffer_size,
|
|
|
|
NULL, &error);
|
|
|
|
|
|
|
|
if (res < 0 && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
|
|
|
|
{
|
|
|
|
g_error_free (error);
|
|
|
|
res = 0;
|
|
|
|
}
|
|
|
|
else if (res <= 0)
|
|
|
|
{
|
|
|
|
g_printerr ("Unable to read from broadway server: %s\n", error ? error->message : "eof");
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
server->recv_buffer_size += res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BroadwayReply *
|
|
|
|
find_response_by_serial (GdkBroadwayServer *server, guint32 serial)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = server->incomming; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
BroadwayReply *reply = l->data;
|
|
|
|
|
|
|
|
if (reply->base.in_reply_to == serial)
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
process_input_messages (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
if (server->process_input_idle != 0)
|
|
|
|
{
|
|
|
|
g_source_remove (server->process_input_idle);
|
|
|
|
server->process_input_idle = 0;
|
|
|
|
}
|
2013-01-08 16:33:29 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
while (server->incomming)
|
|
|
|
{
|
|
|
|
reply = server->incomming->data;
|
|
|
|
server->incomming =
|
|
|
|
g_list_delete_link (server->incomming,
|
|
|
|
server->incomming);
|
|
|
|
|
|
|
|
if (reply->base.type == BROADWAY_REPLY_EVENT)
|
|
|
|
_gdk_broadway_events_got_input (&reply->event.msg);
|
|
|
|
else
|
|
|
|
g_warning ("Unhandled reply type %d\n", reply->base.type);
|
|
|
|
g_free (reply);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
process_input_idle_cb (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
server->process_input_idle = 0;
|
|
|
|
process_input_messages (server);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
queue_process_input_at_idle (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
if (server->process_input_idle == 0)
|
|
|
|
server->process_input_idle =
|
|
|
|
g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)process_input_idle_cb, server, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
input_available_cb (gpointer stream, gpointer user_data)
|
|
|
|
{
|
|
|
|
GdkBroadwayServer *server = user_data;
|
|
|
|
|
|
|
|
read_some_input_nonblocking (server);
|
|
|
|
parse_all_input (server);
|
|
|
|
|
|
|
|
process_input_messages (server);
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BroadwayReply *
|
|
|
|
gdk_broadway_server_wait_for_reply (GdkBroadwayServer *server,
|
|
|
|
guint32 serial)
|
2013-01-08 16:28:49 +00:00
|
|
|
{
|
2012-12-21 23:02:55 +00:00
|
|
|
BroadwayReply *reply;
|
2013-01-08 16:28:49 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
reply = find_response_by_serial (server, serial);
|
|
|
|
if (reply)
|
|
|
|
{
|
|
|
|
server->incomming = g_list_remove (server->incomming, reply);
|
2013-01-08 16:28:49 +00:00
|
|
|
break;
|
2012-12-21 23:02:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
read_some_input_blocking (server);
|
|
|
|
parse_all_input (server);
|
|
|
|
}
|
|
|
|
|
|
|
|
queue_process_input_at_idle (server);
|
2013-01-08 16:28:49 +00:00
|
|
|
return reply;
|
2012-12-21 23:02:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_flush (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
BroadwayRequestFlush msg;
|
|
|
|
|
|
|
|
gdk_broadway_server_send_message(server, msg, BROADWAY_REQUEST_FLUSH);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_sync (GdkBroadwayServer *server)
|
|
|
|
{
|
|
|
|
BroadwayRequestSync msg;
|
|
|
|
guint32 serial;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
serial = gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_SYNC);
|
|
|
|
reply = gdk_broadway_server_wait_for_reply (server, serial);
|
|
|
|
|
|
|
|
g_assert (reply->base.type == BROADWAY_REPLY_SYNC);
|
|
|
|
|
|
|
|
g_free (reply);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_query_mouse (GdkBroadwayServer *server,
|
|
|
|
guint32 *toplevel,
|
|
|
|
gint32 *root_x,
|
|
|
|
gint32 *root_y,
|
|
|
|
guint32 *mask)
|
|
|
|
{
|
|
|
|
BroadwayRequestQueryMouse msg;
|
|
|
|
guint32 serial;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
serial = gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_QUERY_MOUSE);
|
|
|
|
reply = gdk_broadway_server_wait_for_reply (server, serial);
|
|
|
|
|
|
|
|
g_assert (reply->base.type == BROADWAY_REPLY_QUERY_MOUSE);
|
|
|
|
|
|
|
|
if (toplevel)
|
|
|
|
*toplevel = reply->query_mouse.toplevel;
|
|
|
|
if (root_x)
|
|
|
|
*root_x = reply->query_mouse.root_x;
|
|
|
|
if (root_y)
|
|
|
|
*root_y = reply->query_mouse.root_y;
|
|
|
|
if (mask)
|
|
|
|
*mask = reply->query_mouse.mask;
|
|
|
|
|
|
|
|
g_free (reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
guint32
|
|
|
|
_gdk_broadway_server_new_window (GdkBroadwayServer *server,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
gboolean is_temp)
|
|
|
|
{
|
|
|
|
BroadwayRequestNewWindow msg;
|
|
|
|
guint32 serial, id;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
msg.x = x;
|
|
|
|
msg.y = y;
|
|
|
|
msg.width = width;
|
|
|
|
msg.height = height;
|
|
|
|
msg.is_temp = is_temp;
|
|
|
|
|
|
|
|
serial = gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_NEW_WINDOW);
|
|
|
|
reply = gdk_broadway_server_wait_for_reply (server, serial);
|
|
|
|
|
|
|
|
g_assert (reply->base.type == BROADWAY_REPLY_NEW_WINDOW);
|
|
|
|
|
|
|
|
id = reply->new_window.id;
|
|
|
|
|
|
|
|
g_free (reply);
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_destroy_window (GdkBroadwayServer *server,
|
|
|
|
gint id)
|
|
|
|
{
|
|
|
|
BroadwayRequestDestroyWindow msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_DESTROY_WINDOW);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
_gdk_broadway_server_window_show (GdkBroadwayServer *server,
|
|
|
|
gint id)
|
|
|
|
{
|
|
|
|
BroadwayRequestShowWindow msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_SHOW_WINDOW);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
_gdk_broadway_server_window_hide (GdkBroadwayServer *server,
|
|
|
|
gint id)
|
|
|
|
{
|
|
|
|
BroadwayRequestHideWindow msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_HIDE_WINDOW);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-11-12 11:03:50 +00:00
|
|
|
void
|
|
|
|
_gdk_broadway_server_window_focus (GdkBroadwayServer *server,
|
|
|
|
gint id)
|
|
|
|
{
|
|
|
|
BroadwayRequestFocusWindow msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_FOCUS_WINDOW);
|
|
|
|
}
|
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
void
|
|
|
|
_gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
|
|
|
|
gint id, gint parent)
|
|
|
|
{
|
|
|
|
BroadwayRequestSetTransientFor msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
msg.parent = parent;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_SET_TRANSIENT_FOR);
|
|
|
|
}
|
|
|
|
|
2013-06-13 17:35:43 +00:00
|
|
|
static void *
|
|
|
|
map_named_shm (char *name, gsize size)
|
|
|
|
{
|
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
|
|
|
|
int fd;
|
|
|
|
void *ptr;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
fd = shm_open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
|
|
|
|
if (fd == -1)
|
|
|
|
{
|
|
|
|
if (errno != EEXIST)
|
|
|
|
g_error ("Unable to allocate shared mem for window");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = ftruncate (fd, size);
|
|
|
|
g_assert (res != -1);
|
|
|
|
|
|
|
|
res = posix_fallocate (fd, 0, size);
|
|
|
|
if (res != 0)
|
|
|
|
{
|
|
|
|
shm_unlink (name);
|
|
|
|
g_error ("Not enough shared memory for window surface");
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
|
|
|
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
|
|
|
#elif defined(G_OS_WIN32)
|
|
|
|
|
|
|
|
int fd;
|
|
|
|
void *ptr;
|
|
|
|
char *shmpath;
|
|
|
|
void *map = ((void *)-1);
|
|
|
|
int res;
|
|
|
|
|
|
|
|
if (*name == '/')
|
|
|
|
++name;
|
|
|
|
shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
|
|
|
|
|
|
fd = open(shmpath, O_RDWR|O_CREAT|O_EXCL, 0600);
|
|
|
|
g_free (shmpath);
|
|
|
|
if (fd == -1)
|
|
|
|
{
|
|
|
|
if (errno != EEXIST)
|
|
|
|
g_error ("Unable to allocate shared mem for window");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = ftruncate (fd, size);
|
|
|
|
g_assert (res != -1);
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
ptr = map;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
HANDLE h, fm;
|
|
|
|
h = (HANDLE)_get_osfhandle (fd);
|
|
|
|
fm = CreateFileMapping (h, NULL, PAGE_READWRITE, 0, (DWORD)size, NULL);
|
|
|
|
ptr = MapViewOfFile (fm, FILE_MAP_WRITE, 0, 0, (size_t)size);
|
|
|
|
CloseHandle (fm);
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error "No shm mapping supported"
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
static char
|
|
|
|
make_valid_fs_char (char c)
|
|
|
|
{
|
2013-01-10 22:59:23 +00:00
|
|
|
char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
|
|
|
|
|
2013-04-03 13:49:54 +00:00
|
|
|
return chars[c % (sizeof (chars) - 1)];
|
2012-12-21 23:02:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* name must have at least space for 34 bytes */
|
2013-06-13 17:35:43 +00:00
|
|
|
static gpointer
|
|
|
|
create_random_shm (char *name, gsize size)
|
2012-12-21 23:02:55 +00:00
|
|
|
{
|
|
|
|
guint32 r;
|
2013-06-13 17:35:43 +00:00
|
|
|
int i, o;
|
|
|
|
gpointer ptr;
|
2012-12-21 23:02:55 +00:00
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
o = 0;
|
|
|
|
name[o++] = '/';
|
2013-01-10 22:59:23 +00:00
|
|
|
name[o++] = 'b';
|
|
|
|
name[o++] = 'd';
|
|
|
|
name[o++] = 'w';
|
|
|
|
name[o++] = '-';
|
|
|
|
for (i = 0; i < 32/4 - 1; i++)
|
2012-12-21 23:02:55 +00:00
|
|
|
{
|
|
|
|
r = g_random_int ();
|
|
|
|
name[o++] = make_valid_fs_char ((r >> 0) & 0xff);
|
|
|
|
name[o++] = make_valid_fs_char ((r >> 8) & 0xff);
|
|
|
|
name[o++] = make_valid_fs_char ((r >> 16) & 0xff);
|
|
|
|
name[o++] = make_valid_fs_char ((r >> 24) & 0xff);
|
|
|
|
}
|
|
|
|
name[o++] = 0;
|
|
|
|
|
2013-06-13 17:35:43 +00:00
|
|
|
ptr = map_named_shm (name, size);
|
|
|
|
if (ptr)
|
|
|
|
return ptr;
|
2012-12-21 23:02:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const cairo_user_data_key_t gdk_broadway_shm_cairo_key;
|
|
|
|
|
|
|
|
typedef struct {
|
2013-03-18 15:36:27 +00:00
|
|
|
char name[36];
|
2012-12-21 23:02:55 +00:00
|
|
|
void *data;
|
|
|
|
gsize data_size;
|
|
|
|
} BroadwayShmSurfaceData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
shm_data_destroy (void *_data)
|
|
|
|
{
|
|
|
|
BroadwayShmSurfaceData *data = _data;
|
|
|
|
|
2013-06-13 17:35:43 +00:00
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
munmap (data->data, data->data_size);
|
|
|
|
shm_unlink (data->name);
|
2013-06-13 17:35:43 +00:00
|
|
|
|
|
|
|
#elif defined(G_OS_WIN32)
|
|
|
|
|
|
|
|
char *name = data->name;
|
|
|
|
char *shmpath;
|
|
|
|
|
|
|
|
if (*name == '/')
|
|
|
|
++name;
|
|
|
|
|
|
|
|
shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
|
|
UnmapViewOfFile (data->data);
|
|
|
|
remove (shmpath);
|
|
|
|
g_free (shmpath);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
g_free (data);
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_surface_t *
|
|
|
|
_gdk_broadway_server_create_surface (int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
BroadwayShmSurfaceData *data;
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
|
|
|
data = g_new (BroadwayShmSurfaceData, 1);
|
|
|
|
data->data_size = width * height * sizeof (guint32);
|
2013-06-13 17:35:43 +00:00
|
|
|
data->data = create_random_shm (data->name, data->data_size);
|
2012-12-21 23:02:55 +00:00
|
|
|
|
|
|
|
surface = cairo_image_surface_create_for_data ((guchar *)data->data,
|
2013-11-06 11:54:37 +00:00
|
|
|
CAIRO_FORMAT_ARGB32, width, height, width * sizeof (guint32));
|
2012-12-21 23:02:55 +00:00
|
|
|
g_assert (surface != NULL);
|
|
|
|
|
|
|
|
cairo_surface_set_user_data (surface, &gdk_broadway_shm_cairo_key,
|
|
|
|
data, shm_data_destroy);
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_window_update (GdkBroadwayServer *server,
|
|
|
|
gint id,
|
|
|
|
cairo_surface_t *surface)
|
|
|
|
{
|
|
|
|
BroadwayRequestUpdate msg;
|
|
|
|
BroadwayShmSurfaceData *data;
|
|
|
|
|
2012-12-27 21:19:23 +00:00
|
|
|
if (surface == NULL)
|
|
|
|
return;
|
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
data = cairo_surface_get_user_data (surface, &gdk_broadway_shm_cairo_key);
|
|
|
|
g_assert (data != NULL);
|
|
|
|
|
|
|
|
msg.id = id;
|
2013-03-18 15:36:27 +00:00
|
|
|
memcpy (msg.name, data->name, 36);
|
2012-12-21 23:02:55 +00:00
|
|
|
msg.width = cairo_image_surface_get_width (surface);
|
|
|
|
msg.height = cairo_image_surface_get_height (surface);
|
2013-01-08 16:33:29 +00:00
|
|
|
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
2012-12-21 23:02:55 +00:00
|
|
|
BROADWAY_REQUEST_UPDATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
_gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
|
|
|
|
gint id,
|
2013-01-08 16:33:29 +00:00
|
|
|
gboolean with_move,
|
2012-12-21 23:02:55 +00:00
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
BroadwayRequestMoveResize msg;
|
|
|
|
|
|
|
|
msg.id = id;
|
2013-01-08 16:33:29 +00:00
|
|
|
msg.with_move = with_move;
|
2012-12-21 23:02:55 +00:00
|
|
|
msg.x = x;
|
|
|
|
msg.y = y;
|
|
|
|
msg.width = width;
|
|
|
|
msg.height = height;
|
|
|
|
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_MOVE_RESIZE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkGrabStatus
|
|
|
|
_gdk_broadway_server_grab_pointer (GdkBroadwayServer *server,
|
|
|
|
gint id,
|
|
|
|
gboolean owner_events,
|
|
|
|
guint32 event_mask,
|
|
|
|
guint32 time_)
|
|
|
|
{
|
|
|
|
BroadwayRequestGrabPointer msg;
|
|
|
|
guint32 serial, status;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
msg.id = id;
|
|
|
|
msg.owner_events = owner_events;
|
|
|
|
msg.event_mask = event_mask;
|
|
|
|
msg.time_ = time_;
|
|
|
|
|
|
|
|
serial = gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_GRAB_POINTER);
|
|
|
|
reply = gdk_broadway_server_wait_for_reply (server, serial);
|
|
|
|
|
|
|
|
g_assert (reply->base.type == BROADWAY_REPLY_GRAB_POINTER);
|
|
|
|
|
|
|
|
status = reply->grab_pointer.status;
|
2013-01-08 16:33:29 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
g_free (reply);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
guint32
|
|
|
|
_gdk_broadway_server_ungrab_pointer (GdkBroadwayServer *server,
|
|
|
|
guint32 time_)
|
|
|
|
{
|
|
|
|
BroadwayRequestUngrabPointer msg;
|
|
|
|
guint32 serial, status;
|
|
|
|
BroadwayReply *reply;
|
|
|
|
|
|
|
|
msg.time_ = time_;
|
|
|
|
|
|
|
|
serial = gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_UNGRAB_POINTER);
|
|
|
|
reply = gdk_broadway_server_wait_for_reply (server, serial);
|
|
|
|
|
|
|
|
g_assert (reply->base.type == BROADWAY_REPLY_UNGRAB_POINTER);
|
|
|
|
|
|
|
|
status = reply->ungrab_pointer.status;
|
2013-01-08 16:33:29 +00:00
|
|
|
|
2012-12-21 23:02:55 +00:00
|
|
|
g_free (reply);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
2013-11-13 11:20:07 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_broadway_server_set_show_keyboard (GdkBroadwayServer *server,
|
|
|
|
gboolean show)
|
|
|
|
{
|
|
|
|
BroadwayRequestSetShowKeyboard msg;
|
|
|
|
|
|
|
|
msg.show_keyboard = show;
|
|
|
|
gdk_broadway_server_send_message (server, msg,
|
|
|
|
BROADWAY_REQUEST_SET_SHOW_KEYBOARD);
|
|
|
|
}
|