Logo Search packages:      
Sourcecode: afterstep version File versions

module.c

/*
 * Copyright (c) 1999 Ethan Fischer <allanon@crystaltokyo.com>
 * Copyright (C) 1998 Guylhem Aznar
 * Copyright (C) 1993 Robert Nation
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/***********************************************************************
 *
 * code for launching afterstep modules.
 *
 ***********************************************************************/

#define LOCAL_DEBUG

#include "../../configure.h"

#include "asinternals.h"

#include <signal.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>                                    /* for chmod() */
#include <sys/types.h>
#include <sys/un.h>                                            /* for struct sockaddr_un */

#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif

#include <X11/keysym.h>

#include "../../libAfterStep/module.h"
#include "../../libAfterStep/wmprops.h"

static DECL_VECTOR(send_data_type, module_output_buffer);

static void        DeleteQueueBuff (module_t *module);
static void       AddToQueue      (module_t *module, send_data_type *ptr, int size, int done);

int           module_listen (const char *socket_name);


/* create a named UNIX socket, and start watching for connections */
Bool
module_setup_socket ()
{
      char         *tmp;
#ifdef __CYGWIN__
      {                                                              /* there are problems under Windows as home dir could be anywhere  -
                                                                      * so we just use /tmp since there will only be 1 user anyways :) */
        tmp = safemalloc (4 + 9 + 32 + 1);
            /*sprintf (tmp, "/tmp/connect.%s", display_string); */
        sprintf (tmp, "/tmp/as-connect.%ld", Scr.screen);
            fprintf (stderr, "using %s for intermodule communications.\n", tmp);
      }
#else
      {
        char         *display = XDisplayString (dpy);
        char *tmpdir = getenv("TMPDIR");
        static char *default_tmp_dir = "/tmp" ;
        if( tmpdir != NULL )
            if( CheckDir( tmpdir ) < 0 )
                tmpdir = NULL ;

        if( tmpdir == NULL )
            tmpdir = default_tmp_dir ;
      if( access( tmpdir, W_OK ) != 0 )
          if( (tmpdir = getenv( "HOME" )) == NULL )
            return False ;

        tmp = safemalloc (strlen(tmpdir)+11+32 + strlen (display) + 1);
        sprintf (tmp, "%s/afterstep-%d.%s", tmpdir, getuid(), display);
            LOCAL_DEBUG_OUT("using socket \"%s\" for intermodule communications", tmp);
      }
#endif
    set_as_module_socket( Scr.wmprops, tmp );
    Module_fd = socket_listen (tmp);
      free (tmp);

      XSync (dpy, 0);

    return (Module_fd >= 0);
}

void
KillModule (module_t *module, Bool dont_free_memory)
{
LOCAL_DEBUG_OUT( "module %p ", module );
LOCAL_DEBUG_OUT( "module name \"%s\"", module->name );
    if (module->fd > 0)
        close (module->fd);

      if( !dont_free_memory )
      {
      while (module->output_queue != NULL)
            DeleteQueueBuff (module);
      if (module->name != NULL)
            free (module->name);
      if (module->ibuf.text != NULL)
            free (module->ibuf.text);

      if (module->ibuf.func != NULL)
            {
            free_func_data (module->ibuf.func);
            free (module->ibuf.func);
            }

      memset( module, 0x00, sizeof(module_t) );
      }else
      {
            module->output_queue = NULL ;
            module->name = NULL ;
            module->ibuf.text = NULL ;
            module->ibuf.func = NULL ;
      }

      module->fd = -1;
      module->active = -1;
}


/*
 * ReadModuleInput Does actuall read from the module pipe.
 * returns :
 *  0, -1    - error or not enough data
 *  1        - SUCCESS
 */



static int
ReadModuleInput (module_t *module, size_t * offset, size_t size, void *ptr)
{
    size_t        done_this = module->ibuf.done - *offset;
      int           n = size;

      if (done_this >= 0 && done_this < size)
      {
            ptr += done_this;
        n = read (module->fd, ptr, size - done_this);
            if (n > 0)
            {
            module->ibuf.done += n;
            if (module->ibuf.done < *offset + size)
                        return 0;                              /* No more data available */
            } else
                  return (n == -1 && (errno == EINTR || errno == EAGAIN)) ? 0 : -1;
      }
      if (n > 0)
            *offset += n;
      return 1;                                                /* Success */
}

static void
CheckCmdTextSize (module_t *module, CARD32 * size, CARD32 * curr_len, char **text)
{
      /* max command length is 255 */
      if (*size > 255)
      {
        show_error("command from module '%s' is too big (%d)", module->name, *size);
            *size = 255;
      }

      /* need to be able to read in command */
      if (*curr_len < *size + 1)
      {
            *curr_len = *size + 1;
            *text = realloc (*text, *curr_len);
      }
}

/*
 * Higher level protocol handler
 *
 * Two possible protocols :
 * 1. Text command line :
 * <window>< 0<size<256 >< size bytes of text >
 * < continuation_indicator == F_FUNCTIONS_NUM >
 *
 * 2. Preprocessed AS Function data :
 * <window>< size==0 ><function_code>
 *  < 0<name_size<256 >[< name_size bytes of function name >|<nothing if size == 0>]
 *  < 0<text_size<256 >[< size bytes of text >|< nothing if size == 0>]
 *  < 2*sizeof(long) of func_val[] >< 2*sizeof(long) of unit_val >
 * < continuation_indicator == F_FUNCTIONS_NUM >
 *
 * Returns :
 *  -2    - bad module
 *  0, -1 - error or not enough data
 *  > 0   - command execution result
 */

int
HandleModuleInput (module_t *module)
{
      size_t        offset = 0;
    int           res = 1;
    Bool          invalid_func = False;
    register module_ibuf_t *ibuf ;

    ibuf = &(module->ibuf);

    /* read a window id */
    res = ReadModuleInput (module, &offset, sizeof (ibuf->window), &(ibuf->window));
      if (res > 0)
      {
        module->active = 1;
        res = ReadModuleInput (module, &offset, sizeof (ibuf->size), &(ibuf->size));
      }

LOCAL_DEBUG_OUT("res(%d)->window(0x%lX)->size(%ld)",res, ibuf->window, ibuf->size);
      if (res > 0)
      {
            if (ibuf->size > 0)                                /* Protocol 1 */
            {
LOCAL_DEBUG_OUT("Incoming message in proto 1%s","");
            CheckCmdTextSize (module, &(ibuf->size), &(ibuf->len), &(ibuf->text));
            res = ReadModuleInput (module, &offset, ibuf->size, ibuf->text);

            if (res > 0)
                  {
                        /* null-terminate the command line */
                        ibuf->text[ibuf->size] = '\0';
                ibuf->func = String2Func (ibuf->text, ibuf->func, False);
                invalid_func = (ibuf->func== NULL);
            }
            } else                                                   /* Protocol 2 */
            {
            /* for module->afterstep communications - 32 bit values are always used : */
            CARD32        curr_len;
            CARD32        tmp32, tmp32_val[2], tmp32_unit[2] ;
                  register FunctionData *pfunc = ibuf->func;
            int i ;

LOCAL_DEBUG_OUT("Incoming message in proto 2%s","");
            if (pfunc == NULL)
                  {
                        pfunc = (FunctionData *) safemalloc (sizeof (FunctionData));
                        init_func_data (pfunc);
                        ibuf->func = pfunc;
                  }

            res = ReadModuleInput (module, &offset, sizeof (CARD32), &tmp32);
            pfunc->func = tmp32 ;

                  if (res > 0)
                  {
                        if (!IsValidFunc (pfunc->func))
                        {
                              res = 0;
                              ibuf->done = 0;
                    invalid_func = True;
                        } else
                    res = ReadModuleInput (module, &offset, sizeof (ibuf->name_size), &(ibuf->name_size));
                  }
                  if (res > 0 && ibuf->name_size > 0)
                  {
                        curr_len = (pfunc->name) ? strlen (pfunc->name) + 1 : 0;
                CheckCmdTextSize (module, &(ibuf->name_size), &curr_len, &(pfunc->name));
                res = ReadModuleInput (module, &offset, ibuf->name_size, pfunc->name);
                        pfunc->name[ibuf->name_size] = '\0';
                  }
            LOCAL_DEBUG_OUT( "name_size = %ld, pfunc->name = %p", ibuf->name_size, pfunc->name );
            if (res > 0)
                res = ReadModuleInput (module, &offset, sizeof (ibuf->text_size), &(ibuf->text_size));

                  if (res > 0 && ibuf->text_size > 0)
                  {
                        curr_len = (pfunc->text) ? strlen (pfunc->text) + 1 : 0;
                CheckCmdTextSize (module, &(ibuf->text_size), &curr_len, &(pfunc->text));
                res = ReadModuleInput (module, &offset, ibuf->text_size, pfunc->text);
                        pfunc->text[ibuf->text_size] = '\0';
                  }
            LOCAL_DEBUG_OUT( "text_size = %ld, pfunc->text = %p", ibuf->text_size, pfunc->text );
            if (res > 0)
                res = ReadModuleInput (module, &offset, sizeof (tmp32_val), &(tmp32_val[0]));

                  if (res > 0)
                res = ReadModuleInput (module, &offset, sizeof (tmp32_unit), &(tmp32_unit[0]));

            for( i = 0 ; i < MAX_FUNC_ARGS ; ++i )
            {
                pfunc->func_val[i] = tmp32_val[i] ;
                pfunc->unit_val[i] = tmp32_unit[i] ;
            }

                  if (res > 0 && IsValidFunc (pfunc->func))
                invalid_func = False;
            }
      }

      /* get continue command */
      if (res > 0)
      {
        res = ReadModuleInput (module, &offset, sizeof (ibuf->cont), &(ibuf->cont));
            if (res > 0)
            {
                  if (ibuf->cont != F_FUNCTIONS_NUM)
                        if (ibuf->cont != 1)
                              res = -1;
            } else
                  ibuf->cont = 0;
      }

      if (res < 0)
        KillModule (module, False);
    else if (res > 0)
    {
        ibuf->done = 0;                        /* done reading command */
        if( invalid_func )
            res = -1 ;
    }
LOCAL_DEBUG_OUT( "result(%d)", res );
    PRINT_MEM_STATS(NULL);
    return res;
}

static void
AddToQueue (module_t *module, send_data_type *ptr, int size, int done)
{
    register struct queue_buff_struct *new_elem, **tail;

    new_elem = safecalloc (1, sizeof (struct queue_buff_struct));

    new_elem->size = size;
    new_elem->done = done;
    new_elem->data = safemalloc (size);
    memcpy (new_elem->data, ptr, size);
LOCAL_DEBUG_OUT( "que_buff %p: size = %d, done = %d, data = %p", new_elem, size, done, new_elem->data );
    for( tail = &(module->output_queue) ; *tail ; tail = &((*tail)->next) );
    *tail = new_elem;
}

static void
DeleteQueueBuff (module_t *module)
{
    register struct queue_buff_struct *a = module->output_queue;
    if ( a )
    {
        module->output_queue = a->next;
LOCAL_DEBUG_OUT( "deleting buffer %p sent to module %p - next %p ", a, module, a->next );
        free (a->data);
        free (a);
    }
}

int
FlushQueue (module_t *module)
{
      extern int    errno;
    int           fd;
    register struct queue_buff_struct *curr;

    if ( module->active <= 0 )
        return -1;
    if( module->output_queue == NULL )
        return 1;

    fd = module->fd ;
    while( (curr = module->output_queue) != NULL)
      {
        register unsigned char *dptr = curr->data;
        int bytes_written = 0;

        do
        {
            if( (bytes_written = write (fd, &dptr[curr->done], curr->size - curr->done)) > 0 )
                curr->done += bytes_written ;
            LOCAL_DEBUG_OUT( "wrote %d bytes into the module %p pipe", bytes_written, module );
        }while( curr->done < curr->size && bytes_written > 0);

            /* the write returns EWOULDBLOCK or EAGAIN if the pipe is full.
             * (This is non-blocking I/O). SunOS returns EWOULDBLOCK, OSF/1
             * returns EAGAIN under these conditions. Hopefully other OSes
             * return one of these values too. Solaris 2 doesn't seem to have
             * a man page for write(2) (!) */
        if (bytes_written < 0 )
        {
            if(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
            {
               return 0;
            }else
            {
                KillModule (module, False);
                return -1;
            }
        }
        DeleteQueueBuff (module);
      }
    return 1;
}

void
FlushAllQueues()
{
      fd_set        out_fdset;
      int           retval = -1;
      struct timeval tv;
      struct timeval *t = NULL;

      do
      {
            int           max_fd = -1;
        register int i = MIN(MODULES_NUM,Module_npipes) ;
        register module_t *list = MODULES_LIST ;

            FD_ZERO (&out_fdset);

            while( --i >= 0 )
            {
                  if (list[i].fd >= 0 )
                  {

                        int res = 0;
                        if( list[i].output_queue && (retval < 0 || FD_ISSET (list[i].fd, &out_fdset)))
                              FlushQueue (&(list[i]));
                        if( res >= 0 && list[i].output_queue != NULL)
                        {
                              FD_SET (list[i].fd, &out_fdset);
                              if (max_fd < list[i].fd)
                                    max_fd = list[i].fd;
                        }
                  }
            }

            if( max_fd < 0 )
                  return ;/* no more output left */

            tv.tv_sec = 0 ;
            tv.tv_usec = 15000 ;
            t = &tv ;
          retval = PORTABLE_SELECT(min (max_fd + 1, fd_width),NULL,&out_fdset,NULL,t);
            if (retval <= 0)
                  return ;
      }while(1);
}




#include <sys/errno.h>
static inline int
PositiveWrite (unsigned int channel, send_data_type *ptr, int size)
{
    module_t *module = &(MODULES_LIST[channel]);
    register CARD32 mask = ptr[1] ;

    LOCAL_DEBUG_OUT( "module(%p)->active(%d)->module_mask(0x%lX)->mask(0x%lX)", module, module->active, module->mask, mask );
    if (module->active < 0 || !get_flags(module->mask, mask))
            return -1;

      AddToQueue (module, ptr, size, 0);
    if (get_flags(module->lock_on_send_mask, mask) && !is_server_grabbed() )
      {
        int           res ;
            int wait_count = 0 ; 
        do
        {
            if( (res = FlushQueue (module)) >= 0 )
                  {
                        sleep_a_millisec(10);/* give it some time to react */   
                res = HandleModuleInput (module);
            }
                  if ( res > 0  ) /* need to run command */
            {
                        LOCAL_DEBUG_OUT( "replay received while waiting for UNLOCK, func = %ld, F_UNLOCK = %d", module->ibuf.func->func, F_UNLOCK );
                if( module->ibuf.func->func == F_UNLOCK )
                    return size;
                RunCommand (module->ibuf.func, channel, module->ibuf.window);
            }
                  sleep_a_millisec(10);/* give it some time to react */
                  ++wait_count ;
                  /* module has no more then 20 seconds to unlock us */
        }while( res >= 0 && wait_count < 2000 );
      }
      return size;
}

static send_data_type *
make_msg_header( send_data_type msg_type, send_data_type size )
{
    static send_data_type msg_header[MSG_HEADER_SIZE];

    msg_header[0] = START_FLAG ;
    msg_header[1] = msg_type ;
    msg_header[2] = size + MSG_HEADER_SIZE ;
    return &(msg_header[0]);
}

void
SendBuffer( int channel )
{
    send_data_type *b = VECTOR_HEAD(send_data_type,module_output_buffer);
    send_data_type size_to_send ;

    size_to_send = b[2];
    if( size_to_send > 0 && Modules )
      {
            /* lets make sure that we will not overrun the buffer : */
        realloc_vector(&module_output_buffer, size_to_send );
        b = VECTOR_HEAD(send_data_type,module_output_buffer);
LOCAL_DEBUG_OUT( "sending %ld words to module # %d of %d", size_to_send, channel, MODULES_NUM );
        if( channel >= 0 && channel < MODULES_NUM)
            PositiveWrite (channel, b, size_to_send*sizeof(send_data_type) );
          else
            {
            register int i = MODULES_NUM;
            while ( --i >= 0 )
                PositiveWrite (i, b, size_to_send*sizeof(send_data_type));
          }
      }
}



/********************************************************************************/
/* public interfaces :                                                          */
/********************************************************************************/
int
AcceptModuleConnection (int socket_fd)
{
      int           fd;
      int           len = sizeof (struct sockaddr_un);
      struct sockaddr_un name;

      fd = accept (socket_fd, (struct sockaddr *)&name, &len);

      if (fd < 0 && errno != EWOULDBLOCK)
        show_system_error("error accepting connection");

      /* set non-blocking I/O mode */
      if (fd >= 0)
      {
            if (fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK) == -1)
            {
            show_system_error("unable to set non-blocking I/O for module socket");
                  close (fd);
                  fd = -1;
            }
      }

      /* mark as close-on-exec so other programs won't inherit the socket */
      if (fd >= 0)
      {
            if (fcntl (fd, F_SETFD, 1) == -1)
            {
            show_system_error("unable to set close-on-exec for module socket");
                  close (fd);
                  fd = -1;
            }
      }

      if (fd >= 0 && Modules )
      {
        int channel = -1;

        /* Look for an available pipe slot */
        if( MODULES_NUM < Module_npipes-1 )
        {
            module_t   new_module ;
                  memset( &new_module, 0x00, sizeof(module_t) );
            /* add pipe to afterstep's active pipe list */
            new_module.name = mystrdup ("unknown module");
            new_module.fd = fd;
            new_module.active = 0;
            new_module.mask = MAX_MASK;
            new_module.output_queue = NULL;
            /* adding new module to the end of the list */
                  LOCAL_DEBUG_OUT( "adding new module:  total modules %d. list starts at %p", MODULES_NUM, MODULES_LIST );
            channel = vector_insert_elem( Modules, &new_module, 1, NULL, False );
                  LOCAL_DEBUG_OUT( "added module # %d : total modules %d. list starts at %p", channel, MODULES_NUM, MODULES_LIST );

        }
        if( channel < 0 )
        {
            show_error("too many modules!");
                  close (fd);
            fd = -1 ;
            }
    }

      return fd;
}


void
ShutdownModules(Bool dont_free_memory)
{
    if (Modules != NULL)
    {
        register int i = MODULES_NUM;
        register module_t *list = MODULES_LIST ;
LOCAL_DEBUG_OUT( "pid(%d),total modules %d. list starts at %p", getpid(), MODULES_NUM, MODULES_LIST );
        while(--i >= 0 )
            KillModule ( &(list[i]), dont_free_memory );
            if( !dont_free_memory )
            {
LOCAL_DEBUG_OUT( "pid(%d),destroy_asvector", getpid() );
            destroy_asvector(&Modules);
LOCAL_DEBUG_OUT( "pid(%d),free_vector", getpid() );
                  free_vector( &module_output_buffer );
LOCAL_DEBUG_OUT( "pid(%d),modules are down", getpid() );
            }
        Modules = NULL;
    }
}

void
SetupModules(void)
{
    if( Modules )
        ShutdownModules(False);

    Module_npipes = get_fd_width ();
      LOCAL_DEBUG_OUT( "max Module pipes = %d", Module_npipes );
    Modules = create_asvector(sizeof(module_t));
    module_setup_socket ();
}

void
ExecModule (char *action, Window win, int context)
{
      int           val;
    char         *module, *cmd, *args ;

    if (action == NULL || Modules == NULL )
            return;
    args = parse_filename( action, &module );
    if( module == NULL )
        return ;
    if ((cmd = findIconFile (module, Environment->module_path, X_OK)) == NULL)
      {
        show_error("no such module %s in path %s\n", module, Environment->module_path);
        free( module );
        return;
      }
    free( module );

    args = stripcpy( args );
    val = spawn_child( cmd, -1, Scr.screen, win, context, True, True, args, NULL );

    if( args )
        free (args);
    free( cmd );
}


void
HandleModuleInOut(unsigned int channel, Bool has_input, Bool has_output)
{
    int res  = 0;

    if( Modules && channel < MODULES_NUM )
    {
        register module_t *module = &(MODULES_LIST[channel]);
LOCAL_DEBUG_OUT( "module %d has %s input and %s output", channel, has_input?"":"no", has_output?"":"no" );
        if( has_input )
        {
            res = HandleModuleInput( module );
            if( res < 0 )
                has_output = 0 ;
            else if ( res > 0 ) /* need to run command */
                RunCommand (module->ibuf.func, channel, module->ibuf.window);
        }
        if( has_output )
            FlushQueue( module );
      }
}

void
DeadPipe (int nonsense)
{
      signal (SIGPIPE, DeadPipe);
}


void
KillModuleByName (char *name)
{
    wild_reg_exp  *wrexp = compile_wild_reg_exp( name );

    if ( wrexp != NULL && Modules)
    {
        register int i = MODULES_NUM;
        register module_t *list = MODULES_LIST ;

        while( --i >= 0 )
            if (list[i].fd > 0)
            {
                LOCAL_DEBUG_OUT( "checking to kill module %d \"%s\", regexp \"%s\"", i, list[i].name, name);
                if (match_wild_reg_exp( list[i].name, wrexp ) == 0 )
                    KillModule (&(list[i]), False);
            }
        destroy_wild_reg_exp( wrexp );
    }
      return;
}

void
SendPacket ( int channel, send_data_type msg_type, send_data_type num_datum, ...)
{
      va_list       ap;
    register send_data_type *body;
    int i ;

    flush_vector( &module_output_buffer );
    append_vector( &module_output_buffer, make_msg_header(msg_type,num_datum), MSG_HEADER_SIZE );

    append_vector( &module_output_buffer, NULL, num_datum);
    body = VECTOR_TAIL(send_data_type,module_output_buffer) ;

    va_start (ap, num_datum);
      for (i = 0; i < num_datum; i++)
        *(body++) = va_arg (ap, send_data_type);

    VECTOR_USED(module_output_buffer) += num_datum;
      va_end (ap);

    SendBuffer( channel );
}


void
SendConfig (int module, send_data_type event_type, ASWindow * t)
{
    send_signed_data_type     frame_x = 0, frame_y = 0, frame_width = 0, frame_height = 0;
    send_ID_type              icon_title_w = None, icon_pixmap_w = None ;
    send_signed_data_type     icon_x = 0, icon_y = 0, icon_width = 0, icon_height = 0 ;
      union {
            ASWindow *asw ;
            send_data_type id ;
      }asw_id;

    if( t->frame_canvas )
    {
        frame_x = t->frame_canvas->root_x ;
        frame_y = t->frame_canvas->root_y ;
        if( !ASWIN_GET_FLAGS(t, AS_Sticky) )
        {
            frame_x += t->status->viewport_x ;
            frame_y += t->status->viewport_y ;
        }
        frame_width = t->frame_canvas->width+t->frame_canvas->bw*2 ;
        frame_height = t->frame_canvas->height+t->frame_canvas->bw*2 ;
    }

    if( t->icon_canvas )
        icon_pixmap_w = t->icon_canvas->w ;
    if( t->icon_title_canvas && t->icon_title_canvas != t->icon_canvas )
        icon_title_w = t->icon_title_canvas->w ;

    if (ASWIN_GET_FLAGS(t,AS_Iconic))
    {
        ASCanvas *ic = t->icon_canvas?t->icon_canvas:t->icon_title_canvas ;
        if( ic != NULL )
        {
            icon_x = ic->root_x ;
            icon_y = ic->root_y ;
            icon_width = ic->width+ic->bw*2 ;
            icon_height = ic->height+ic->bw*2;
        }
    }

      asw_id.asw = t ;
    SendPacket (module, event_type, 25,
                t->w,                 t->frame,              asw_id.id,
                frame_x,              frame_y,               frame_width,         frame_height,
                ASWIN_DESK(t),        t->status->flags,      t->hints->flags,
                t->hints->base_width, t->hints->base_height, t->hints->width_inc, t->hints->height_inc,
                t->hints->min_width,  t->hints->min_height,  t->hints->max_width,  t->hints->max_height,
                t->hints->gravity,    icon_title_w,          icon_pixmap_w,
                icon_x,               icon_y,                icon_width,           icon_height );
}

void
SendString ( int channel, send_data_type msg_type,
             Window w, Window frame, ASWindow *asw_ptr,
                   char *string, send_data_type encoding )
{
    send_data_type                  data[3];
    send_signed_data_type     len = 0;
      union {
            ASWindow *asw ;
            send_data_type id ;
      }asw_id;

    if (string == NULL)
            return;
    len = strlen(string);

    flush_vector( &module_output_buffer );
    append_vector( &module_output_buffer,
                    make_msg_header(msg_type,3+1+(len>>2)+1+MSG_HEADER_SIZE),
                    MSG_HEADER_SIZE );
    data[0] = w;
    data[1] = frame;
      asw_id.asw = asw_ptr ;
      data[2] = asw_id.id;
    append_vector( &module_output_buffer, &(data[0]), 3);
    append_vector( &module_output_buffer, &encoding, 1);
    serialize_string( string, &module_output_buffer );
    SendBuffer( channel );
}

void
SendVector (int channel, send_data_type msg_type, ASVector *vector)
{
    if (vector == NULL )
            return;

    flush_vector( &module_output_buffer );
    append_vector( &module_output_buffer,
                    make_msg_header(msg_type,VECTOR_USED(*vector)),
                    MSG_HEADER_SIZE );
    append_vector( &module_output_buffer, VECTOR_HEAD(send_data_type,*vector), VECTOR_USED(*vector));

    SendBuffer( channel );
}

void
SendStackingOrder (int channel, send_data_type msg_type, send_data_type desk, ASVector *ids)
{
    send_data_type data[2];

    if (ids == NULL )
            return;

    flush_vector( &module_output_buffer );
    append_vector( &module_output_buffer,
                    make_msg_header(msg_type,VECTOR_USED(*ids)+2),
                    MSG_HEADER_SIZE );
    data[0] = desk ;
    data[1] = VECTOR_USED(*ids);
    append_vector( &module_output_buffer, &(data[0]), 2);
    append_vector( &module_output_buffer, VECTOR_HEAD(send_data_type,*ids), VECTOR_USED(*ids));

    SendBuffer( channel );
}

/* this will run command received from module */
void
RunCommand (FunctionData * fdata, unsigned int channel, Window w)
{
      ASWindow     *tmp_win;
    int           toret = 0;
    module_t     *module;

    LOCAL_DEBUG_CALLER_OUT( "fdata(%p)->func(%ld,MOD_FS=%d)->channel(%d)->w(%lX)->Modules(%p)", fdata, fdata->func, F_MODULE_FUNC_START, channel, w, Modules );
/*fprintf( stderr,"Function parsed: [%s] [%s] [%d] [%d] [%c]\n",fdata.name,fdata.text,fdata.func_val[0], fdata.func_val[1] );
 */
    if (Modules == NULL || fdata == NULL || channel >= MODULES_NUM )
        return;
    if (!IsValidFunc(fdata->func))
        return;
    module = &(MODULES_LIST[channel] );
    switch (fdata->func)
      {
       case F_SET_MASK:
         module->mask = fdata->func_val[0];
             module->lock_on_send_mask = fdata->func_val[1];
             break;
       case F_SET_NAME:
        if (module->name != NULL)
            free (module->name);
        module->name = fdata->name;
        fdata->name = NULL;
        break;
     case F_UNLOCK:
             toret = 66;
             break;
       case F_SET_FLAGS:
             {
                   int           xorflag;
                   Bool          update = False;

             if ((tmp_win = window2ASWindow(w)) == NULL)
                         break;
             xorflag = tmp_win->hints->flags ^ fdata->func_val[0];
                   /*if (xorflag & STICKY)
                      Stick (tmp_win); */
                   if (xorflag & AS_SkipWinList)
                   {
                         tmp_win->hints->flags ^= AS_SkipWinList;
                         update = True;
                   }
                   if (xorflag & AS_AvoidCover)
                   {
                         tmp_win->hints->flags ^= AS_AvoidCover;
                         update = True;
                   }
                   if (xorflag & AS_Transient)
                   {
                         tmp_win->hints->flags ^= AS_Transient;
                         update = True;
                   }
                   if (xorflag & AS_DontCirculate)
                   {
                         tmp_win->hints->flags ^= AS_DontCirculate;
                         update = True;
                   }
                   if (update)
                 broadcast_config (M_CONFIGURE_WINDOW, tmp_win);
                   break;
             }
       default:
        {
            ASEvent event;
            memset( &event, 0x00, sizeof(ASEvent) );
            event.w = w;
            if ((event.client = window2ASWindow(w)) == NULL )
            {
                event.w = None;
                event.x.xbutton.x_root = 0;
                event.x.xbutton.y_root = 0;
            } else
            {
                event.x.xbutton.x_root = event.client->frame_canvas->root_x+1;
                event.x.xbutton.y_root = event.client->frame_canvas->root_y+1;
            }
            event.x.xany.type = ButtonRelease;
            event.x.xbutton.button = 1;
            event.x.xbutton.x = 0;
            event.x.xbutton.y = 0;
            event.x.xbutton.subwindow = None;
            event.context = C_FRAME;
            event.scr = ASDefaultScr ;
            event.event_time = Scr.last_Timestamp ;
            /* there must be no deffering on module commands ! */
            ExecuteFunctionExt (fdata, &event, channel, True);
        }
    }
    free_func_data (fdata);
}

/*******************************************************************************/
/* usefull functions to simplify life in other places :                        */
/*******************************************************************************/
void
broadcast_focus_change( ASWindow *asw, Bool focused )
{
      union {
            ASWindow *asw ;
            send_data_type id ;
      }asw_id;

      asw_id.asw = asw ;
      if( asw )
        SendPacket(-1, M_FOCUS_CHANGE, 4, asw->w, asw->frame, asw_id.id, (send_data_type)focused);
}

void
broadcast_window_name( ASWindow *asw )
{
    if( asw )
      {     
        SendString( -1, M_WINDOW_NAME, asw->w, asw->frame,
                    asw, ASWIN_NAME(asw), asw->hints->names_encoding[0]);
        SendString( -1, M_WINDOW_NAME_MATCHED, asw->w, asw->frame,
                    asw, asw->hints->matched_name0, asw->hints->matched_name0_encoding );
      }
}

void
broadcast_icon_name( ASWindow *asw )
{
    if( asw )
        SendString( -1, M_ICON_NAME, asw->w, asw->frame,
                    asw, ASWIN_ICON_NAME(asw), asw->hints->names_encoding[asw->hints->icon_name_idx]);
}

void
broadcast_res_names( ASWindow *asw )
{
    if( asw )
    {
        SendString( -1, M_RES_CLASS, asw->w, asw->frame,
                    asw, asw->hints->res_class, asw->hints->names_encoding[asw->hints->res_class_idx]);
        SendString( -1, M_RES_NAME, asw->w, asw->frame,
                    asw, asw->hints->res_name, asw->hints->names_encoding[asw->hints->res_name_idx]);
    }
}

void
broadcast_status_change( int message, ASWindow *asw )
{
      union {
            ASWindow *asw ;
            send_data_type id ;
      }asw_id;

      asw_id.asw = asw ;

    if( message == M_MAP )
        SendPacket( -1, M_MAP, 3, asw->w, asw->frame, asw_id.id);
}

void
broadcast_config (send_data_type event_type, ASWindow * t)
{
    SendConfig( -1, event_type, t );
}


Generated by  Doxygen 1.6.0   Back to index