diff options
author | Alexander Larsson <alexl@redhat.com> | 2001-06-25 23:01:36 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2001-06-25 23:01:36 +0000 |
commit | 75fd7f09af9de7691ef46e12cad6ac243298c16e (patch) | |
tree | 1da19b6e074adcbbf53cbfdf4b88f803cc42a33f | |
parent | 4168b4780317921000f88d2e58f2b66ae6ce7038 (diff) | |
download | gdk-pixbuf-75fd7f09af9de7691ef46e12cad6ac243298c16e.tar.gz |
Added --enable-fbmanager. This is some experimental code that lets several
2001-06-25 Alexander Larsson <alexl@redhat.com>
* configure.in:
Added --enable-fbmanager. This is some experimental code
that lets several GtkFB apps coordinate their access to the
framebuffer.
* acconfig.h:
Added ENABLE_FB_MANAGER.
* gdk/linux-fb/Makefile.am:
Added gdkfbmanager and gdkfbswitch.
* gdk/linux-fb/gdkkeyboard-fb.c:
* gdk/linux-fb/gdkmouse-fb.c:
* gdk/linux-fb/gdkprivate-fb.h:
Split device init and open so that
they can be opened and closed while switched
away.
* gdk/linux-fb/gdkmain-fb.c:
Add the basic manager communication.
* gdk/linux-fb/gdkrender-fb.c:
Don't update to the shadow fb if we're
blocked by the fb manager.
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 27 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 27 | ||||
-rw-r--r-- | acconfig.h | 3 | ||||
-rw-r--r-- | configure.in | 10 | ||||
-rw-r--r-- | gdk/linux-fb/Makefile.am | 15 | ||||
-rw-r--r-- | gdk/linux-fb/gdkfbmanager.c | 406 | ||||
-rw-r--r-- | gdk/linux-fb/gdkfbmanager.h | 37 | ||||
-rw-r--r-- | gdk/linux-fb/gdkfbswitch.c | 75 | ||||
-rw-r--r-- | gdk/linux-fb/gdkkeyboard-fb.c | 31 | ||||
-rw-r--r-- | gdk/linux-fb/gdkmain-fb.c | 166 | ||||
-rw-r--r-- | gdk/linux-fb/gdkmouse-fb.c | 73 | ||||
-rw-r--r-- | gdk/linux-fb/gdkprivate-fb.h | 8 | ||||
-rw-r--r-- | gdk/linux-fb/gdkrender-fb.c | 3 |
18 files changed, 977 insertions, 39 deletions
@@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index e94c717f1..a91bdb655 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,30 @@ +2001-06-25 Alexander Larsson <alexl@redhat.com> + + * configure.in: + Added --enable-fbmanager. This is some experimental code + that lets several GtkFB apps coordinate their access to the + framebuffer. + + * acconfig.h: + Added ENABLE_FB_MANAGER. + + * gdk/linux-fb/Makefile.am: + Added gdkfbmanager and gdkfbswitch. + + * gdk/linux-fb/gdkkeyboard-fb.c: + * gdk/linux-fb/gdkmouse-fb.c: + * gdk/linux-fb/gdkprivate-fb.h: + Split device init and open so that + they can be opened and closed while switched + away. + + * gdk/linux-fb/gdkmain-fb.c: + Add the basic manager communication. + + * gdk/linux-fb/gdkrender-fb.c: + Don't update to the shadow fb if we're + blocked by the fb manager. + Sun Jun 24 22:15:16 2001 Owen Taylor <otaylor@redhat.com> * docs/Changes-2.0.txt: Add note about child property diff --git a/acconfig.h b/acconfig.h index f2f4b4a1e..37cd31587 100644 --- a/acconfig.h +++ b/acconfig.h @@ -50,6 +50,9 @@ /* Define to use shadowfb in the linux-fb port */ #undef ENABLE_SHADOW_FB +/* Define to use a fb manager in the linux-fb port */ +#undef ENABLE_FB_MANAGER + #undef XINPUT_NONE #undef XINPUT_GXI #undef XINPUT_XFREE diff --git a/configure.in b/configure.in index 3b8eba5d7..1f7e1a942 100644 --- a/configure.in +++ b/configure.in @@ -135,6 +135,8 @@ case $gdktarget in esac AC_ARG_ENABLE(shadowfb, [ --disable-shadowfb disable shadowfb support for linux-fb],,enable_shadowfb=yes) + +AC_ARG_ENABLE(fbmanager, [ --enable-fbmanager enable framebuffer manager support (GtkFB)],enable_fbmanager=yes,enable_fbmanager=no) if test "x$enable_debug" = "xyes"; then test "$cflags_set" = set || CFLAGS="$CFLAGS -g" @@ -852,6 +854,13 @@ if test "x$gdktarget" = "xlinux-fb"; then if test x$enable_shadowfb = xyes ; then AC_DEFINE(ENABLE_SHADOW_FB) fi + + if test x$enable_fbmanager = xyes ; then + AC_DEFINE(ENABLE_FB_MANAGER) + AM_CONDITIONAL(ENABLE_FB_MANAGER, true) + else + AM_CONDITIONAL(ENABLE_FB_MANAGER, false) + fi GDK_EXTRA_CFLAGS="$FREETYPE_CFLAGS" GDK_EXTRA_LIBS="$FREETYPE_LIBS $GDK_EXTRA_LIBS" @@ -859,6 +868,7 @@ if test "x$gdktarget" = "xlinux-fb"; then AM_CONDITIONAL(USE_LINUX_FB, true) else AM_CONDITIONAL(USE_LINUX_FB, false) + AM_CONDITIONAL(ENABLE_FB_MANAGER, false) fi AC_SUBST(gdktargetlib) diff --git a/gdk/linux-fb/Makefile.am b/gdk/linux-fb/Makefile.am index 795f15d9a..4e0f37eb2 100644 --- a/gdk/linux-fb/Makefile.am +++ b/gdk/linux-fb/Makefile.am @@ -1,5 +1,11 @@ ## Process this file with automake to produce Makefile.in +if ENABLE_FB_MANAGER +bin_PROGRAMS = gdkfbmanager gdkfbswitch +else +bin_PROGRAMS = +endif + libgdkincludedir = $(includedir)/gtk-2.0/gdk libgdkfbincludedir = $(includedir)/gtk-2.0/gdk/linux-fb @@ -61,14 +67,17 @@ libgdk_linux_fb_la_SOURCES = \ mipolyutil.c \ miscanfill.h \ mispans.h \ + mispans.c \ mistruct.h \ mitypes.h \ miwideline.c \ miwideline.h \ mizerclip.c \ mizerline.c \ - mispans.c \ - gdkpango-fb.c - mispans.c + gdkpango-fb.c \ + gdkfbmanager.h + +gdkfbmanager_sources = gdkfbmanager.c +gdkfbswitch_sources = gdkfbswitch.c EXTRA_DIST=x-cursors.xbm diff --git a/gdk/linux-fb/gdkfbmanager.c b/gdk/linux-fb/gdkfbmanager.c new file mode 100644 index 000000000..23cc49501 --- /dev/null +++ b/gdk/linux-fb/gdkfbmanager.c @@ -0,0 +1,406 @@ +#include <glib.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/types.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> + +#include "gdkfbmanager.h" + +typedef struct { + int socket; + int pid; /* -1 if not initialized */ +} Client; + +GHashTable *clients = NULL; +GHashTable *new_clients = NULL; +Client *current_owner = NULL; + +int master_socket; + +int create_master_socket (void) +{ + int fd; + struct sockaddr_un addr; + + fd = socket (PF_UNIX, SOCK_STREAM, 0); + + if (fd < 0) + { + printf ("Error creating socket: %s\n", strerror(errno)); + return -1; + } + + unlink ("/tmp/.fb.manager"); + + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "/tmp/.fb.manager"); + + if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) + { + printf ("Unable to bind socket: %s\n", strerror(errno)); + close (fd); + return -1; + } + + + if (listen (fd, 10) < 0) + { + printf ("Unable to listen on socket: %s\n", strerror(errno)); + close (fd); + return -1; + } + + master_socket = fd; + return 0; +} + +void +handle_new_client (void) +{ + int fd; + Client *client; + int true_val; + + fd = accept (master_socket, NULL, NULL); + + client = g_new (Client, 1); + client->socket = fd; + client->pid = -1; + + true_val = 1; + setsockopt (fd, SOL_SOCKET, SO_PASSCRED, + &true_val, sizeof (true_val)); + + g_print ("Handling new client %p conntecting, fd = %d\n", client, fd); + + g_hash_table_insert (new_clients, client, client); +} + +struct fd_data +{ + fd_set *read_fds; + fd_set *exception_fds; + int max_fd; +}; + +void +send_message (Client *client, enum FBManagerMessageType type, int data) +{ + struct FBManagerMessage msg; + + msg.msg_type = type; + msg.data = data; + + send (client->socket, &msg, sizeof (msg), 0); +} + +gboolean +wait_for_ack (Client *client, int timeout_secs) +{ + struct FBManagerMessage msg; + int res; + fd_set rfds; + struct timeval tv; + + while (1) + { + FD_ZERO(&rfds); + FD_SET(client->socket, &rfds); + + tv.tv_sec = timeout_secs; + tv.tv_usec = 0; + + res = select (client->socket+1, &rfds, NULL, NULL, &tv); + + if (res == 0) + return FALSE; + + res = recv (client->socket, &msg, sizeof (msg), 0); + if (res != sizeof (msg)) + return FALSE; + + if (msg.msg_type == FB_MANAGER_ACK) + return TRUE; + } +} + +void +find_another_client (gpointer key, + gpointer value, + gpointer user_data) +{ + Client **res; + Client *client; + + res = user_data; + + if (*res) + return; + + client = value; + if (client != current_owner) + *res = client; +} + +void +switch_to_client (Client *client) +{ + g_print ("Switch_to_client, client=%p, current_owner=%p\n", client, current_owner); + + if ((current_owner == client) && (client != NULL)) + return; + + if (current_owner) + { + g_print ("switching from client fd=%d\n", current_owner->socket); + send_message (current_owner, FB_MANAGER_SWITCH_FROM, 0); + wait_for_ack (current_owner, 3); + } + + current_owner = client; + + if (current_owner) + { + g_print ("switching to client fd=%d\n", current_owner->socket); + send_message (current_owner, FB_MANAGER_SWITCH_TO, 0); + } +} + +void +close_client (Client *client) +{ + Client *other_client; + g_print ("Closing client %p (fd=%d)\n", + client, client->socket); + + if (current_owner == client) + { + other_client = NULL; + g_hash_table_foreach (clients, + find_another_client, + &other_client); + current_owner = NULL; + /* FIXME: This is a hack around the fact that the serial + mouse driver had problems with opening and closing + the device almost at the same time. + */ + sleep (1); + switch_to_client (other_client); + } + + close (client->socket); + g_free (client); +} + + +/* Returns TRUE if the client was closed */ +gboolean +read_client_data (Client *client) +{ + struct FBManagerMessage fb_message; + struct msghdr msg; + struct iovec iov; + char control_buffer[256]; + struct cmsghdr *cmsg; + int res; + struct ucred *creds; + Client *new_client; + + iov.iov_base = &fb_message; + iov.iov_len = sizeof (fb_message); + + cmsg = (struct cmsghdr *)control_buffer; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg; + msg.msg_controllen = 256; + msg.msg_flags = 0; + + g_print ("Reading client data:"); + res = recvmsg (client->socket, &msg, 0); + g_print ("%d bytes, (error: %s)\n", res, + strerror (errno)); + + if (res < 0) + return FALSE; + + if (res == 0) + { + close_client (client); + return TRUE; + } + + if (res != sizeof (fb_message)) + { + g_warning ("Packet with wrong size %d recieved", res); + return FALSE; + } + + switch (fb_message.msg_type) { + case FB_MANAGER_NEW_CLIENT: + if (client->pid != -1) + { + g_warning ("Got a NEW_CLIENT message from an old client"); + return FALSE; + } + creds = NULL; + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg,cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) + { + creds = (struct ucred *) CMSG_DATA(cmsg); + break; + } + } + if (creds == NULL) + { + g_warning ("Got no credentials in NEW_CLIENT message"); + close_client (client); + return TRUE; + } + client->pid = creds->pid; + + g_hash_table_insert (clients, GINT_TO_POINTER (client->pid), client); + + g_print ("New client connected. Pid=%d\n", (int)creds->pid); + return TRUE; + break; + case FB_MANAGER_REQUEST_SWITCH_TO_PID: + if (client->pid == -1) + { + g_warning ("Got a message from an uninitialized client"); + return FALSE; + } + + new_client = g_hash_table_lookup (clients, GINT_TO_POINTER (fb_message.data)); + if (new_client) + switch_to_client (new_client); + else + g_warning ("Switchto unknown PID"); + break; + case FB_MANAGER_ACK: + if (client->pid == -1) + { + g_warning ("Got a message from an uninitialized client"); + return FALSE; + } + g_warning ("Got an unexpected ACK"); + break; + default: + g_warning ("Got unknown package type %d", fb_message.msg_type); + break; + } + return FALSE; +} + +/* Returns TRUE if the client was closed */ +gboolean +handle_client_data (gpointer key, + gpointer value, + gpointer user_data) +{ + Client *client; + struct fd_data *data; + + client = value; + data = user_data; + + if (FD_ISSET (client->socket, data->exception_fds)) + { + close_client (client); + return TRUE; + } + else if (FD_ISSET (client->socket, data->read_fds)) + { + return read_client_data (client); + } + + return FALSE; +} + +void +set_fds (gpointer key, + gpointer value, + gpointer user_data) +{ + struct fd_data *data; + Client *client; + + client = value; + data = user_data; + + FD_SET (client->socket, data->read_fds); + FD_SET (client->socket, data->exception_fds); + data->max_fd = MAX (data->max_fd, + client->socket); +} + +void +main_loop (void) +{ + fd_set read_fds; + fd_set exception_fds; + struct fd_data data; + int res; + + while (1) + { + FD_ZERO (&read_fds); + FD_ZERO (&exception_fds); + FD_SET (master_socket, &read_fds); + + data.read_fds = &read_fds; + data.exception_fds = &exception_fds; + data.max_fd = master_socket; + + g_hash_table_foreach (clients, + set_fds, + &data); + g_hash_table_foreach (new_clients, + set_fds, + &data); + + + res = select (data.max_fd+1, + &read_fds, NULL, &exception_fds, + NULL); + + if (FD_ISSET (master_socket, &read_fds)) + handle_new_client (); + + g_hash_table_foreach_remove (clients, + handle_client_data, + &data); + g_hash_table_foreach_remove (new_clients, + handle_client_data, + &data); + } +} + + +int +main (int argc, char *argv[]) +{ + clients = g_hash_table_new (g_direct_hash, + g_direct_equal); + new_clients = g_hash_table_new (g_direct_hash, + g_direct_equal); + + create_master_socket (); + + main_loop (); + + return 0; +} diff --git a/gdk/linux-fb/gdkfbmanager.h b/gdk/linux-fb/gdkfbmanager.h new file mode 100644 index 000000000..653a1c69c --- /dev/null +++ b/gdk/linux-fb/gdkfbmanager.h @@ -0,0 +1,37 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GDK_FB_MANAGER_H__ +#define __GDK_FB_MANAGER_H__ + +enum FBManagerMessageType { + /* manager -> client */ + FB_MANAGER_SWITCH_TO, + FB_MANAGER_SWITCH_FROM, /* requires ack */ + + /* client -> manager */ + FB_MANAGER_NEW_CLIENT, + FB_MANAGER_REQUEST_SWITCH_TO_PID, + FB_MANAGER_ACK, +}; + +struct FBManagerMessage { + enum FBManagerMessageType msg_type; + int data; +}; +#endif /* __GDK_FB_MANAGER_H__ */ diff --git a/gdk/linux-fb/gdkfbswitch.c b/gdk/linux-fb/gdkfbswitch.c new file mode 100644 index 000000000..707325f8f --- /dev/null +++ b/gdk/linux-fb/gdkfbswitch.c @@ -0,0 +1,75 @@ +#include <glib.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "gdkfbmanager.h" + +int +main (int argc, char *argv[]) +{ + int fd; + struct sockaddr_un addr; + struct msghdr msg = {0}; + struct cmsghdr *cmsg; + struct ucred credentials; + struct FBManagerMessage init_msg; + struct iovec iov; + char buf[CMSG_SPACE (sizeof (credentials))]; /* ancillary data buffer */ + int *fdptr; + int res; + + if (argc != 2) + { + g_print ("usage: fbswitch <pid>\n"); + return 1; + } + + fd = socket (PF_UNIX, SOCK_STREAM, 0); + + if (fd < 0) + return 1; + + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "/tmp/.fb.manager"); + + if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) + { + g_print ("connect failed\n"); + close (fd); + return 1; + } + + credentials.pid = getpid (); + credentials.uid = geteuid (); + credentials.gid = getegid (); + + init_msg.msg_type = FB_MANAGER_NEW_CLIENT; + iov.iov_base = &init_msg; + iov.iov_len = sizeof (init_msg); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof buf; + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN (sizeof (credentials)); + /* Initialize the payload: */ + fdptr = (int *)CMSG_DATA (cmsg); + memcpy (fdptr, &credentials, sizeof (credentials)); + /* Sum of the length of all control messages in the buffer: */ + msg.msg_controllen = cmsg->cmsg_len; + + res = sendmsg (fd, &msg, 0); + + init_msg.msg_type = FB_MANAGER_REQUEST_SWITCH_TO_PID; + init_msg.data = atoi (argv[1]); + /* Request a switch-to */ + send (fd, &init_msg, sizeof (init_msg), 0); + g_print ("requested a switch to pid %d\n", init_msg.data); +} diff --git a/gdk/linux-fb/gdkkeyboard-fb.c b/gdk/linux-fb/gdkkeyboard-fb.c index c5c8993ca..2aebfff76 100644 --- a/gdk/linux-fb/gdkkeyboard-fb.c +++ b/gdk/linux-fb/gdkkeyboard-fb.c @@ -167,17 +167,18 @@ gdk_fb_keyboard_modifiers () } gboolean -gdk_fb_keyboard_open (void) +gdk_fb_keyboard_init (gboolean open_dev) { GdkFBKeyboard *keyb; - GdkFBKeyboardDevice *device; char *keyb_type; int i; - keyb = g_new0 (GdkFBKeyboard, 1); + gdk_fb_keyboard = g_new0 (GdkFBKeyboard, 1); + keyb = gdk_fb_keyboard; keyb->fd = -1; keyb_type = getenv ("GDK_KEYBOARD_TYPE"); + if (!keyb_type) keyb_type = "xlate"; @@ -193,19 +194,29 @@ gdk_fb_keyboard_open (void) return FALSE; } - device = &keyb_devs[i]; + keyb->dev = &keyb_devs[i]; + + if (open_dev) + return gdk_fb_keyboard_open (); + else + return TRUE; +} + +gboolean +gdk_fb_keyboard_open (void) +{ + GdkFBKeyboard *keyb; + GdkFBKeyboardDevice *device; + + keyb = gdk_fb_keyboard; + device = keyb->dev; - keyb->dev = device; - if (!device->open(keyb)) { g_warning ("Keyboard driver open failed"); - g_free (keyb); return FALSE; } - gdk_fb_keyboard = keyb; - return TRUE; } @@ -213,7 +224,6 @@ void gdk_fb_keyboard_close (void) { gdk_fb_keyboard->dev->close(gdk_fb_keyboard); - g_free (gdk_fb_keyboard); } @@ -903,6 +913,7 @@ xlate_close (GdkFBKeyboard *kb) g_source_remove (kb->io_tag); g_io_channel_unref (kb->io); + kb->fd = -1; /* don't close kb->fd, it is the tty from gdk_display */ } diff --git a/gdk/linux-fb/gdkmain-fb.c b/gdk/linux-fb/gdkmain-fb.c index 77318ddee..6f0357e40 100644 --- a/gdk/linux-fb/gdkmain-fb.c +++ b/gdk/linux-fb/gdkmain-fb.c @@ -39,10 +39,14 @@ #include <sys/kd.h> #include <errno.h> +#include <sys/socket.h> +#include <sys/un.h> + #include "gdk.h" #include "gdkprivate-fb.h" #include "gdkinternals.h" +#include "gdkfbmanager.h" /* Private variable declarations */ @@ -484,6 +488,159 @@ gdk_fb_set_mode (GdkFBDisplay *display) return 0; } +#ifdef ENABLE_FB_MANAGER +static void +gdk_fb_switch_from (void) +{ + g_print ("Switch from\n"); + gdk_shadow_fb_stop_updates (); + gdk_fb_mouse_close (); + gdk_fb_keyboard_close (); +} + +static void +gdk_fb_switch_to (void) +{ + g_print ("switch_to\n"); + gdk_shadow_fb_update (0, 0, + gdk_display->fb_width, + gdk_display->fb_height); + + if (!gdk_fb_keyboard_open ()) + g_warning ("Failed to re-initialize keyboard"); + + if (!gdk_fb_mouse_open ()) + g_warning ("Failed to re-initialize mouse"); + +} + + +static gboolean +gdk_fb_manager_callback (GIOChannel *gioc, + GIOCondition cond, + gpointer data) +{ + struct FBManagerMessage msg; + GdkFBDisplay *display; + int res; + + display = data; + + res = recv (display->manager_fd, &msg, sizeof (msg), 0); + + if (res==0) + { + g_source_remove (gdk_display->manager_tag); + /*g_io_channel_unref (kb->io);*/ + close (gdk_display->manager_fd); + + } + + if (res != sizeof (msg)) + { + g_warning ("Got wrong size message"); + return TRUE; + } + + switch (msg.msg_type) + { + case FB_MANAGER_SWITCH_FROM: + g_print ("Got switch from message\n"); + display->manager_blocked = TRUE; + gdk_fb_switch_from (); + msg.msg_type = FB_MANAGER_ACK; + send (display->manager_fd, &msg, sizeof (msg), 0); + break; + case FB_MANAGER_SWITCH_TO: + g_print ("Got switch to message\n"); + display->manager_blocked = FALSE; + gdk_fb_switch_to (); + break; + default: + g_warning ("Got unknown message"); + } + return TRUE; +} + +#endif /* ENABLE_FB_MANAGER */ + +static void +gdk_fb_manager_connect (GdkFBDisplay *display) +{ + int fd; + struct sockaddr_un addr; + struct msghdr msg = {0}; + struct cmsghdr *cmsg; + struct ucred credentials; + struct FBManagerMessage init_msg; + struct iovec iov; + char buf[CMSG_SPACE (sizeof (credentials))]; /* ancillary data buffer */ + int *fdptr; + int res; + + display->manager_blocked = FALSE; + display->manager_fd = -1; + +#ifdef ENABLE_FB_MANAGER + fd = socket (PF_UNIX, SOCK_STREAM, 0); + + g_print ("socket: %d\n", fd); + + if (fd < 0) + return; + + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "/tmp/.fb.manager"); + + if (connect(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) + { + g_print ("connect failed\n"); + close (fd); + return; + } + + credentials.pid = getpid (); + credentials.uid = geteuid (); + credentials.gid = getegid (); + + init_msg.msg_type = FB_MANAGER_NEW_CLIENT; + iov.iov_base = &init_msg; + iov.iov_len = sizeof (init_msg); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof buf; + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN (sizeof (credentials)); + /* Initialize the payload: */ + fdptr = (int *)CMSG_DATA (cmsg); + memcpy (fdptr, &credentials, sizeof (credentials)); + /* Sum of the length of all control messages in the buffer: */ + msg.msg_controllen = cmsg->cmsg_len; + + res = sendmsg (fd, &msg, 0); + + display->manager_fd = fd; + display->manager_blocked = TRUE; + + display->manager_tag = g_io_add_watch (g_io_channel_unix_new (fd), + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + gdk_fb_manager_callback, + display); + + init_msg.msg_type = FB_MANAGER_REQUEST_SWITCH_TO_PID; + init_msg.data = getpid (); + + /* Request a switch-to */ + send (fd, &init_msg, sizeof (init_msg), 0); +#endif +} + static GdkFBDisplay * gdk_fb_display_new () { @@ -658,7 +815,9 @@ _gdk_windowing_init_check (int argc, char **argv) gdk_shadow_fb_init (); - if (!gdk_fb_keyboard_open ()) + gdk_fb_manager_connect (gdk_display); + + if (!gdk_fb_keyboard_init (!gdk_display->manager_blocked)) { g_warning ("Failed to initialize keyboard"); gdk_fb_display_destroy (gdk_display); @@ -666,7 +825,7 @@ _gdk_windowing_init_check (int argc, char **argv) return FALSE; } - if (!gdk_fb_mouse_open ()) + if (!gdk_fb_mouse_init (!gdk_display->manager_blocked)) { g_warning ("Failed to initialize mouse"); gdk_fb_keyboard_close (); @@ -678,6 +837,7 @@ _gdk_windowing_init_check (int argc, char **argv) gdk_initialized = TRUE; gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE); + return TRUE; } @@ -1041,8 +1201,10 @@ gdk_windowing_exit (void) { gdk_fb_mouse_close (); + /*leak g_free (gdk_fb_mouse);*/ gdk_fb_keyboard_close (); + /*leak g_free (gdk_fb_keyboard);*/ gdk_fb_display_destroy (gdk_display); diff --git a/gdk/linux-fb/gdkmouse-fb.c b/gdk/linux-fb/gdkmouse-fb.c index 5e6fc3de5..e89ab67b5 100644 --- a/gdk/linux-fb/gdkmouse-fb.c +++ b/gdk/linux-fb/gdkmouse-fb.c @@ -27,6 +27,8 @@ #include <sys/ioctl.h> #include <string.h> #include <math.h> +#include <unistd.h> +#include <errno.h> typedef struct _GdkFBMouse GdkFBMouse; typedef struct _GdkFBMouseDevice GdkFBMouseDevice; @@ -275,21 +277,19 @@ static GdkFBMouseDevice mouse_devs[] = } }; - gboolean -gdk_fb_mouse_open (void) +gdk_fb_mouse_init (gboolean open_dev) { - GdkFBMouse *mouse; - GdkFBMouseDevice *device; char *mouse_type; int i; - mouse = g_new0 (GdkFBMouse, 1); - mouse->fd = -1; + gdk_fb_mouse = g_new0 (GdkFBMouse, 1); + gdk_fb_mouse->fd = -1; + mouse_type = getenv ("GDK_MOUSE_TYPE"); if (!mouse_type) mouse_type = "ps2"; - + for (i=0;i<G_N_ELEMENTS(mouse_devs);i++) { if (g_strcasecmp(mouse_type, mouse_devs[i].name)==0) @@ -302,34 +302,56 @@ gdk_fb_mouse_open (void) return FALSE; } - device = &mouse_devs[i]; + gdk_fb_mouse->dev = &mouse_devs[i]; - mouse->dev = device; - - mouse->x = gdk_display->fb_width / 2; - mouse->y = gdk_display->fb_height / 2; + gdk_fb_mouse->x = gdk_display->fb_width / 2; + gdk_fb_mouse->y = gdk_display->fb_height / 2; + + if (open_dev) + return gdk_fb_mouse_open (); + else + return TRUE; +} + +gboolean +gdk_fb_mouse_open (void) +{ + GdkFBMouseDevice *device; + + device = gdk_fb_mouse->dev; - if (!device->open(mouse)) + if (!device->open(gdk_fb_mouse)) { g_warning ("Mouse driver open failed"); - g_free (mouse); return FALSE; } - mouse->io = g_io_channel_unix_new (mouse->fd); - mouse->io_tag = g_io_add_watch (mouse->io, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, handle_mouse_io, mouse); + gdk_fb_mouse->io = + g_io_channel_unix_new (gdk_fb_mouse->fd); + gdk_fb_mouse->io_tag = + g_io_add_watch (gdk_fb_mouse->io, + G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, + handle_mouse_io, gdk_fb_mouse); - gdk_fb_mouse = mouse; return TRUE; } void gdk_fb_mouse_close (void) { - g_source_remove (gdk_fb_mouse->io_tag); - gdk_fb_mouse->dev->close(gdk_fb_mouse); - g_io_channel_unref (gdk_fb_mouse->io); - g_free (gdk_fb_mouse); + if (gdk_fb_mouse->io_tag) + { + g_source_remove (gdk_fb_mouse->io_tag); + gdk_fb_mouse->io_tag = 0; + } + + gdk_fb_mouse->dev->close(gdk_fb_mouse); + + if (gdk_fb_mouse->io) + { + g_io_channel_unref (gdk_fb_mouse->io); + gdk_fb_mouse->io = NULL; + } } static gboolean @@ -427,6 +449,7 @@ static void gdk_fb_mouse_ps2_close (GdkFBMouse *mouse) { close (mouse->fd); + mouse->fd = -1; } static gboolean @@ -500,8 +523,11 @@ gdk_fb_mouse_ms_open (GdkFBMouse *mouse) struct termios tty; fd = gdk_fb_mouse_dev_open ("/dev/mouse", O_RDWR); - if (fd < 0) - return FALSE; + if (fd < 0) + { + g_print ("Error opening /dev/mouse: %s\n", strerror (errno)); + return FALSE; + } while ((i = read (fd, buf, sizeof(buf))) > 0) g_print ("Got %d bytes of junk from /dev/mouse\n", i); @@ -526,6 +552,7 @@ static void gdk_fb_mouse_ms_close (GdkFBMouse *mouse) { close (mouse->fd); + mouse->fd = -1; } static gboolean diff --git a/gdk/linux-fb/gdkprivate-fb.h b/gdk/linux-fb/gdkprivate-fb.h index 672ba6053..c7b12f611 100644 --- a/gdk/linux-fb/gdkprivate-fb.h +++ b/gdk/linux-fb/gdkprivate-fb.h @@ -148,6 +148,11 @@ struct _GdkFBDisplay struct fb_var_screeninfo modeinfo; struct fb_var_screeninfo orig_modeinfo; int red_byte, green_byte, blue_byte; /* For truecolor */ + + /* fb manager */ + int manager_fd; + int manager_tag; + int manager_blocked; }; typedef struct { @@ -414,7 +419,6 @@ extern GdkEventMask _gdk_fb_keyboard_grab_events; extern gboolean _gdk_fb_keyboard_grab_owner_events; extern GdkFBDisplay *gdk_display; -extern GdkDrawableClass _gdk_fb_drawable_class; extern FILE *debug_out; GdkEvent *gdk_event_make(GdkWindow *window, GdkEventType type, @@ -436,8 +440,10 @@ void gdk_fb_redraw_all(void); void gdk_fb_cursor_move (gint x, gint y, GdkWindow *in_window); guint gdk_fb_keyboard_modifiers (void); +gboolean gdk_fb_keyboard_init (gboolean open_dev); gboolean gdk_fb_keyboard_open (void); void gdk_fb_keyboard_close (void); +gboolean gdk_fb_mouse_init (gboolean open_dev); gboolean gdk_fb_mouse_open (void); void gdk_fb_mouse_close (void); void gdk_fb_mouse_get_info (gint *x, diff --git a/gdk/linux-fb/gdkrender-fb.c b/gdk/linux-fb/gdkrender-fb.c index 8db3e53d9..d63d6732a 100644 --- a/gdk/linux-fb/gdkrender-fb.c +++ b/gdk/linux-fb/gdkrender-fb.c @@ -1405,6 +1405,9 @@ void gdk_shadow_fb_update (gint minx, gint miny, gint maxx, gint maxy) { struct itimerval timeout; + + if (gdk_display->manager_blocked) + return; g_assert (minx <= maxx); g_assert (miny <= maxy); |