Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gdkbroadway-server.c

  Sprache: C
 

#include "config.h"

#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>

#include "gdkbroadway-server.h"

#include "gdkprivate-broadway.h"
#include "gdkprivate.h"

#include <gdk/gdktextureprivate.h>

#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gunixsocketaddress.h>
#include <gio/gunixfdmessage.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#elif defined (G_OS_WIN32)
#include <io.h>
#define ftruncate _chsize_s
#endif
#include <sys/types.h>
#ifdef G_OS_WIN32
#include <windows.h>
#endif
#include <glib/gi18n-lib.h>

typedef struct BroadwayInput BroadwayInput;

struct _GdkBroadwayServer {
  GObject parent_instance;
  GdkDisplay *display;

  guint32 next_serial;
  guint32 next_texture_id;
  GSocketConnection *connection;

  guint32 recv_buffer_size;
  guint8 recv_buffer[1024];

  guint process_input_idle;
  GList *incoming;
};

struct _GdkBroadwayServerClass
{
  GObjectClass parent_class;
};

static gboolean input_available_cb (gpointer stream, gpointer user_data);

static GType gdk_broadway_server_get_type (void);

G_DEFINE_TYPE (GdkBroadwayServer, gdk_broadway_server, G_TYPE_OBJECT)

static void
gdk_broadway_server_init (GdkBroadwayServer *server)
{
  server->next_serial = 1;
  server->next_texture_id = 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 *
_gdk_broadway_server_new (GdkDisplay *display,
                          const char *display_name,
                          GError **error)
{
  GdkBroadwayServer *server;
  GSocketClient *client;
  GSocketConnection *connection;
  GSocketAddress *address;
  GPollableInputStream *pollable;
  GInputStream *in;
  GSource *source;
  char *local_socket_type = NULL;
  int port;

  if (display_name == NULL)
    display_name = ":0";

  if (display_name[0] == ':' && g_ascii_isdigit(display_name[1]))
    {
      char *path, *basename;

      port = strtol (display_name + 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_PATH);
      g_free (path);
    }
  else
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                   _("Broadway display type not supported: %s"), display_name);
      return NULL;
    }

  g_free (local_socket_type);

  client = g_socket_client_new ();

  connection = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (address), NULL, error);

  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;
  server->display = display;

  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;
}

static guint32
gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayRequestBase *base,
                                            gsize size, guint32 type, int fd)
{
  GOutputStream *out;
  gsize written;
  guchar *buf;

  base->size = size;
  base->type = type;
  base->serial = server->next_serial++;

  buf = (guchar *)base;

  if (fd != -1)
    {
      GUnixFDList *fd_list = g_unix_fd_list_new_from_array (&fd, 1);
      GSocketControlMessage *control_message = g_unix_fd_message_new_with_fd_list (fd_list);
      GSocket *socket = g_socket_connection_get_socket (server->connection);
      GOutputVector vector;
      gssize bytes_written;

      vector.buffer = buf;
      vector.size = size;

      bytes_written = g_socket_send_message (socket,
                                             NULL, /* address */
                                             &vector,
                                             1,
                                             &control_message, 1,
                                             G_SOCKET_MSG_NONE,
                                             NULL,
                                             NULL);

      if (bytes_written <= 0)
        {
          g_printerr ("Unable to write to server\n");
          exit (1);
        }

      buf += bytes_written;
      size -= bytes_written;

      g_object_unref (control_message);
      g_object_unref (fd_list);
    }

  if (size > 0)
    {
      out = g_io_stream_get_output_stream (G_IO_STREAM (server->connection));
      if (!g_output_stream_write_all (out, buf, 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, -1)

#define gdk_broadway_server_send_fd_message(_server, _msg, _type, _fd)      \
  gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type, _fd)

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_memdup2 (p, size);
      p += size;

      server->incoming = g_list_append (server->incoming, reply);
    }

  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->incoming; 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;

  g_clear_handle_id (&server->process_input_idle, g_source_remove);

  while (server->incoming)
    {
      reply = server->incoming->data;
      server->incoming =
        g_list_delete_link (server->incoming,
                            server->incoming);

      if (reply->base.type == BROADWAY_REPLY_EVENT)
        _gdk_broadway_events_got_input (server->display, &reply->event.msg);
      else
        g_warning ("Unhandled reply type %d", 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)
{
  BroadwayReply *reply;

  while (TRUE)
    {
      reply = find_response_by_serial (server, serial);
      if (reply)
        {
          server->incoming = g_list_remove (server->incoming, reply);
          break;
        }

      read_some_input_blocking (server);
      parse_all_input (server);
    }

  queue_process_input_at_idle (server);
  return reply;
}

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_roundtrip (GdkBroadwayServer *server,
                                gint32            id,
                                guint32           tag)
{
  BroadwayRequestRoundtrip msg;

  msg.id = id;
  msg.tag = tag;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_ROUNDTRIP);
}

void
_gdk_broadway_server_query_mouse (GdkBroadwayServer *server,
                                  guint32            *surface,
                                  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 (surface)
    *surface = reply->query_mouse.surface;
  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_surface (GdkBroadwayServer *server,
                                 int x,
                                 int y,
                                 int width,
                                 int height)
{
  BroadwayRequestNewSurface msg;
  guint32 serial, id;
  BroadwayReply *reply;

  msg.x = x;
  msg.y = y;
  msg.width = width;
  msg.height = height;
  serial = gdk_broadway_server_send_message (server, msg,
                                             BROADWAY_REQUEST_NEW_SURFACE);
  reply = gdk_broadway_server_wait_for_reply (server, serial);

  g_assert (reply->base.type == BROADWAY_REPLY_NEW_SURFACE);

  id = reply->new_surface.id;

  g_free (reply);

  return id;
}

void
_gdk_broadway_server_destroy_surface (GdkBroadwayServer *server,
                                     int id)
{
  BroadwayRequestDestroySurface msg;

  msg.id = id;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_DESTROY_SURFACE);
}

gboolean
_gdk_broadway_server_surface_show (GdkBroadwayServer *server,
                                  int id)
{
  BroadwayRequestShowSurface msg;

  msg.id = id;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_SHOW_SURFACE);

  return TRUE;
}

gboolean
_gdk_broadway_server_surface_hide (GdkBroadwayServer *server,
                                  int id)
{
  BroadwayRequestHideSurface msg;

  msg.id = id;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_HIDE_SURFACE);

  return TRUE;
}

void
_gdk_broadway_server_surface_focus (GdkBroadwayServer *server,
                                   int id)
{
  BroadwayRequestFocusSurface msg;

  msg.id = id;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_FOCUS_SURFACE);
}

void
_gdk_broadway_server_surface_set_transient_for (GdkBroadwayServer *server,
                                               int id, int parent)
{
  BroadwayRequestSetTransientFor msg;

  msg.id = id;
  msg.parent = parent;
  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_SET_TRANSIENT_FOR);
}

void
_gdk_broadway_server_surface_set_modal_hint (GdkBroadwayServer *server,
                                             int id, gboolean modal_hint)
{
  BroadwayRequestSetModalHint msg;

  msg.id = id;
  msg.modal_hint = modal_hint;
  gdk_broadway_server_send_message (server, msg,
        BROADWAY_REQUEST_SET_MODAL_HINT);
}

static int
open_shared_memory (void)
{
  static gboolean force_shm_open = FALSE;
  int ret = -1;

#if !defined (HAVE_MEMFD_CREATE)
  force_shm_open = TRUE;
#endif

  do
    {
#if defined (HAVE_MEMFD_CREATE)
      if (!force_shm_open)
        {
          ret = memfd_create ("gdk-broadway", MFD_CLOEXEC);

          /* fall back to shm_open until debian stops shipping 3.16 kernel
           * See bug 766341
           */

          if (ret < 0 && errno == ENOSYS)
            force_shm_open = TRUE;
        }
#endif

      if (force_shm_open)
        {
          char name[NAME_MAX - 1] = "";

          sprintf (name, "/gdk-broadway-%x", g_random_int ());

          ret = shm_open (name, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);

          if (ret >= 0)
            shm_unlink (name);
          else if (errno == EEXIST)
            continue;
        }
    }
  while (ret < 0 && errno == EINTR);

  if (ret < 0)
    g_critical (G_STRLOC ": creating shared memory file (using %s) failed: %m",
                force_shm_open? "shm_open" : "memfd_create");

  return ret;
}

guint32
gdk_broadway_server_upload_texture (GdkBroadwayServer *server,
                                    GdkTexture        *texture)
{
  guint32 id;
  BroadwayRequestUploadTexture msg;
  GBytes *bytes;
  const guchar *data;
  gsize size;
  int fd;

  bytes = gdk_texture_save_to_png_bytes (texture);
  fd = open_shared_memory ();
  data = g_bytes_get_data (bytes, &size);

  id = server->next_texture_id++;

  msg.id = id;
  msg.offset = 0;
  msg.size = 0;

  while (msg.size < size)
    {
      gssize ret = write (fd, data + msg.size, size - msg.size);

      if (ret <= 0)
        {
          if (errno == EINTR)
            continue;
          break;
        }

      msg.size += ret;
    }

  g_bytes_unref (bytes);

  /* This passes ownership of fd */
  gdk_broadway_server_send_fd_message (server, msg,
                                       BROADWAY_REQUEST_UPLOAD_TEXTURE, fd);

  return id;
}


void
gdk_broadway_server_release_texture (GdkBroadwayServer *server,
                                     guint32            id)
{
  BroadwayRequestReleaseTexture msg;

  msg.id = id;

  gdk_broadway_server_send_message (server, msg,
                                    BROADWAY_REQUEST_RELEASE_TEXTURE);
}

void
gdk_broadway_server_surface_set_nodes (GdkBroadwayServer *server,
                                      guint32 id,
                                      GArray *nodes)
{
  gsize size = sizeof(BroadwayRequestSetNodes) + sizeof(guint32) * (nodes->len - 1);
  BroadwayRequestSetNodes *msg = g_alloca (size);
  int i;

  for (i = 0; i < nodes->len; i++)
    msg->data[i] = g_array_index (nodes, guint32, i);

  msg->id = id;
  gdk_broadway_server_send_message_with_size (server, (BroadwayRequestBase *) msg, size, BROADWAY_REQUEST_SET_NODES, -1);
}

gboolean
_gdk_broadway_server_surface_move_resize (GdkBroadwayServer *server,
                                         int id,
                                         gboolean with_move,
                                         int x,
                                         int y,
                                         int width,
                                         int height)
{
  BroadwayRequestMoveResize msg;

  msg.id = id;
  msg.with_move = with_move;
  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,
                                   int id,
                                   gboolean owner_events,
                                   guint32 time_)
{
  BroadwayRequestGrabPointer msg;
  guint32 serial, status;
  BroadwayReply *reply;

  msg.id = id;
  msg.owner_events = owner_events;
  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;

  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;

  g_free (reply);

  return status;
}

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);
}

Messung V0.5 in Prozent
C=98 H=96 G=96

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik