Logo Search packages:      
Sourcecode: beryl-core version File versions

session.c

/*
 * Copyright © 2005 Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Author: Radek Doulik <rodo@novell.com>
 */

#ifdef HAVE_CONFIG_H
#  include "../config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <X11/SM/SMlib.h>
#include <X11/ICE/ICElib.h>

#include <beryl.h>
#include <beryl-private.h>

#define SM_DEBUG(x)

static SmcConn smcConnection;
static CompWatchFdHandle iceWatchFdHandle;
static Bool connected = 0;
static Bool iceConnected = 0;
static char *smClientId;

static void iceInit(void);

static void
saveYourselfGotProps(SmcConn connection,
                               SmPointer client_data, int num_props, SmProp ** props)
{
      int p, i;

      for (p = 0; p < num_props; p++)
      {
            if (!strcmp(props[p]->name, SmRestartCommand))
            {
                  for (i = 0; i < props[p]->num_vals - 1; i++)
                  {
                        if (!strncmp(props[p]->vals[i].value,
                                           "--sm-client-id", props[p]->vals[i].length))
                        {
                              SmPropValue oldVal = props[p]->vals[i + 1];

                              props[p]->vals[i + 1].value = smClientId;
                              props[p]->vals[i + 1].length = strlen(smClientId);
                              SmcSetProperties(connection, 1, &props[p]);
                              props[p]->vals[i + 1] = oldVal;

                              SmcSaveYourselfDone(connection, 1);
                              return;
                        }
                  }
            }
      }

      SmcSaveYourselfDone(connection, 1);
}

static void
saveYourselfCallback(SmcConn connection,
                               SmPointer client_data,
                               int saveType,
                               Bool shutdown, int interact_Style, Bool fast)
{
      if (!SmcGetProperties(connection, saveYourselfGotProps, NULL))
            SmcSaveYourselfDone(connection, 1);
}

static void dieCallback(SmcConn connection, SmPointer clientData)
{
      closeSession();
      exit(0);
}

static void saveCompleteCallback(SmcConn connection, SmPointer clientData)
{
}

static void
shutdownCancelledCallback(SmcConn connection, SmPointer clientData)
{
}

void initSession(char *smPrevClientId)
{
      static SmcCallbacks callbacks;

      if (getenv("SESSION_MANAGER"))
      {
            char errorBuffer[1024];

            iceInit();

            callbacks.save_yourself.callback = saveYourselfCallback;
            callbacks.save_yourself.client_data = NULL;

            callbacks.die.callback = dieCallback;
            callbacks.die.client_data = NULL;

            callbacks.save_complete.callback = saveCompleteCallback;
            callbacks.save_complete.client_data = NULL;

            callbacks.shutdown_cancelled.callback = shutdownCancelledCallback;
            callbacks.shutdown_cancelled.client_data = NULL;

            smcConnection = SmcOpenConnection(NULL,
                                                              NULL,
                                                              SmProtoMajor,
                                                              SmProtoMinor,
                                                              SmcSaveYourselfProcMask |
                                                              SmcDieProcMask |
                                                              SmcSaveCompleteProcMask |
                                                              SmcShutdownCancelledProcMask,
                                                              &callbacks,
                                                              smPrevClientId,
                                                              &smClientId,
                                                              sizeof(errorBuffer), errorBuffer);
            if (!smcConnection)
                  fprintf(stderr,
                              "%s: SmcOpenConnection failed: %s\n",
                              programName, errorBuffer);
            else
                  connected = TRUE;
      }
}

void closeSession(void)
{
      if (connected)
      {
            if (SmcCloseConnection(smcConnection, 0, NULL) != SmcConnectionInUse)
                  connected = FALSE;
            if (smClientId)
            {
                  free(smClientId);
                  smClientId = NULL;
            }
      }
}

/* ice connection handling taken and updated from gnome-ice.c
 * original gnome-ice.c code written by Tom Tromey <tromey@cygnus.com>
 */

/* This is called when data is available on an ICE connection. */
static Bool iceProcessMessages(void *data)
{
      IceConn connection = (IceConn) data;
      IceProcessMessagesStatus status;

      SM_DEBUG(printf("ICE connection process messages\n"));

      status = IceProcessMessages(connection, NULL, NULL);

      if (status == IceProcessMessagesIOError)
      {
            SM_DEBUG(printf("ICE connection process messages"
                                    " - error => shutting down the connection\n"));

            IceSetShutdownNegotiation(connection, False);
            IceCloseConnection(connection);
      }

      return 1;
}

/* This is called when a new ICE connection is made.  It arranges for
   the ICE connection to be handled via the event loop.  */
static void
iceNewConnection(IceConn connection,
                         IcePointer clientData, Bool opening, IcePointer * watchData)
{
      if (opening)
      {
            SM_DEBUG(printf("ICE connection opening\n"));

            /* Make sure we don't pass on these file descriptors to any
               exec'ed children */
            fcntl(IceConnectionNumber(connection), F_SETFD,
                    fcntl(IceConnectionNumber(connection),
                              F_GETFD, 0) | FD_CLOEXEC);

            iceWatchFdHandle =
                        compAddWatchFd(IceConnectionNumber(connection),
                                             POLLIN | POLLPRI | POLLHUP | POLLERR,
                                             iceProcessMessages, connection);

            iceConnected = 1;
      }
      else
      {
            SM_DEBUG(printf("ICE connection closing\n"));

            if (iceConnected)
            {
                  compRemoveWatchFd(iceWatchFdHandle);

                  iceWatchFdHandle = 0;
                  iceConnected = 0;
            }
      }
}

static IceIOErrorHandler oldIceHandler;

static void iceErrorHandler(IceConn connection)
{
      if (oldIceHandler)
            (*oldIceHandler) (connection);
}

/* We call any handler installed before (or after) iceInit but
   avoid calling the default libICE handler which does an exit() */
static void iceInit(void)
{
      static Bool iceInitialized = 0;

      if (!iceInitialized)
      {
            IceIOErrorHandler defaultIceHandler;

            oldIceHandler = IceSetIOErrorHandler(NULL);
            defaultIceHandler = IceSetIOErrorHandler(iceErrorHandler);

            if (oldIceHandler == defaultIceHandler)
                  oldIceHandler = NULL;

            IceAddConnectionWatch(iceNewConnection, NULL);

            iceInitialized = 1;
      }
}

Generated by  Doxygen 1.6.0   Back to index