Logo Search packages:      
Sourcecode: afterstep version File versions

asetroot.c

/*
 * Copyright (c) 1998 Sasha Vasko <sasha at aftercode.net>
 * Original idea: Copyright (c) 1998 Rafal Wierzbicki <rafal@mcss.mcmaster.ca>
 *
 * 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.
 *
 */

/*#define DO_CLOCKING      */
#include "../../configure.h"

#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/wait.h>
#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

/*#define DO_CLOCKING */

#ifdef ISC              /* Saul */
#include <sys/bsdtypes.h>     /* Saul */
#endif /* Saul */

#include <stdlib.h>
#if defined ___AIX || defined _AIX || defined __QNX__ || defined ___AIXV3 || defined AIXV3 || defined _SEQUENT_
#include <sys/select.h>
#endif

#define IN_MODULE
#define MODULE_X_INTERFACE

#include "../../libAfterImage/afterimage.h"
#include "../../include/aftersteplib.h"
#include "../../include/afterstep.h"
#include "../../include/style.h"
#include "../../include/mystyle.h"
#include "../../include/screen.h"
#include "../../include/parser.h"
#include "../../include/confdefs.h"
#include "../../include/module.h"
#include "../../include/loadimg.h"
#include "../../include/background.h"

#ifdef DEBUG_ASETROOT
#define LOG1(a)       fprintf( stderr, a );
#define LOG2(a,b)    fprintf( stderr, a, b );
#define LOG3(a,b,c)    fprintf( stderr, a, b, c );
#define LOG4(a,b,c,d)    fprintf( stderr, a, b, c, d );
#else
#define LOG1(a)
#define LOG2(a,b)
#define LOG3(a,b,c)
#define LOG4(a,b,c,d)
#endif


#ifdef DEBUG_ALLOCS
#undef XFreePixmap
#endif

/*************************************************************************
 *
 * Screen, font, etc info
 *
 **************************************************************************/
ASPipes Pipes;
ASAtom Atoms[] =
{XROOTPMAP_ID_ATOM_DEF,
 {None, "_AS_STYLE", XA_INTEGER},
 AS_BACKGROUND_ATOM_DEF,
 {None, "WM_STATE", XA_INTEGER},    /*  it is actually of WM_STATE type,
                                 but we don't know this atom untill
                                 we get it from X */
 {None, NULL, None}
};

#define ROOTPIXMAP_ATOM       0
#define MYSTYLE_ATOM          1
#define BACKGROUND_ATOM       2
#define WM_STATE_ATOM         3


char *MyName;
ScreenInfo Scr;               /* AS compatible screen information structure */
int screen;

char *pixmapPath = NULL;
ASImageManager *ImMan = NULL;

ASDeskBackArray DesksArray =
{NULL, 0};

#define ASETROOT_CONFIG "asetroot"

void
usage (void)
{
  printf ("Usage:\n%s [--version|-v] [--help|-h] [n [m]] [--loadonly|-l]|[--kill|-k]\n", MyName);
  printf ("If started without parameters, %s will load all configured backgrounds\n", MyName);
  printf ("into memory, and will be switching backgrounds for all desks.\n");
  printf ("You can limit number of desks that will be served, by specifying\n");
  printf ("lower range (n), and optionally upper range(m).\n\n");
  printf ("Note: if you only want to load images into memory and use other \n");
  printf ("      module to switch them when desk is changed, use --loadonly(-l) option.\n");
  printf ("      Later on you will be able to remove loaded images from the memory\n");
  printf ("      by running asetroot with --kill(-k) option.\n");

  exit (0);
}

void
ShowAsStarted ()
{
  XTextProperty name;
  Window w;
  XClassHint class1;
  XSizeHints shints;
  int waiting_for_withdrawal = 1;

  w = XCreateSimpleWindow (dpy, Scr.Root, -10000, -10000, 1, 1, 1, 0, 0);

  XStringListToTextProperty (&MyName, 1, &name);

  class1.res_name = MyName;   /* for future use */
  class1.res_class = "ASModule";

  shints.flags = USPosition | USSize;
  shints.min_width = shints.min_height = 4;
  shints.max_width = shints.max_height = 5;
  shints.base_width = shints.base_height = 4;

  XSetWMProperties (dpy, w, &name, &name, NULL, 0, &shints, NULL, &class1);
  /* showing window to let user see that we are doing something */
  XMapRaised (dpy, w);
  /* final cleanup */
  XFree ((char *) name.value);
  XFlush (dpy);
  sleep (1);                  /* we have to give AS a chance to spot us */
  /* we will need to wait for PropertyNotify event indicating transition
     into Withdrawn state, so selecting event mask: */
  XSelectInput (dpy, w, PropertyChangeMask);

  XUnmapWindow (dpy, w);
  /* according to ICCCM we must follow this with synthetic UnmapNotify event */
  {
    XEvent e;
    e.xunmap.type = UnmapNotify;
    e.xunmap.event = Scr.Root;
    e.xunmap.window = w;
    e.xunmap.from_configure = False;

    XSendEvent (dpy, Scr.Root, False, SubstructureRedirectMask | SubstructureNotifyMask, &e);

    while (waiting_for_withdrawal)
      {
      XNextEvent (dpy, &e);
      if (e.type == PropertyNotify && e.xproperty.atom == Atoms[WM_STATE_ATOM].atom)
        {
          Atom act_type;
          int act_format;
          unsigned long nitems, bytes_after;
          unsigned char *prop = NULL;

          if (e.xproperty.state == PropertyDelete)
            {
            break;
            }
          if (XGetWindowProperty (dpy, w, Atoms[WM_STATE_ATOM].atom, 0, 1,
                            False, Atoms[WM_STATE_ATOM].atom, &act_type, &act_format, &nitems,
                            &bytes_after, &prop) == Success)
            if (prop)
            {
              if (*prop == WithdrawnState)
                waiting_for_withdrawal = 0;
              XFree (prop);
            }
        }
      }
    /* we are in withdrawn state now - can safely destroy our window */
  }

  XSelectInput (dpy, w, 0);
  XDestroyWindow (dpy, w);
  XFlush (dpy);
}


void DeadPipe (int nonsense);
void process_message (unsigned long type, unsigned long *body);
void list_new_desk (unsigned long *body);
void list_new_background (unsigned long *body);
void list_unknown (unsigned long *body);
int IsDeskInRange (long desks);
void DeleteMyBackgrounds (ASDeskBackArray * backs, int verbose);
void UpdateBackgroundProperty ();
void GetOptions (const char *filename);
void GetBaseOptions (const char *filename);
void
DispatchEvent (XEvent * Event)
{
};

typedef struct
  {
    char *global_config_file;
    int desk1, desk2;
#define ACTION_DEFAULT  0
#define ACTION_LOADONLY 1
#define ACTION_CLEANUP  2
    int action;
  }
ASetRootEnvironment;

ASetRootEnvironment MyEnv =
{NULL, -1, -1, ACTION_DEFAULT};

/***********************************************************************
 *
 *   Procedure:
 *   main - start of module
 *
 ***********************************************************************/
int
main (int argc, char **argv)
{
  int i, desks[2] =
  {-1, -1}, curr_desk = 0;

  /* it's too complicated to track when to purge pixmap cache in case
     of changed backgrounds, so we just turn it off completely .
     Methods to avoid image loading from the same file twice are
     built in to the asetroot configuration file !!!!!
   */
  set_use_pixmap_ref (FALSE);

  /* Save our program name - for error messages */
  set_application_name(argv[0]);
  SetMyName (argv[0]);

  i = ProcessModuleArgs (argc, argv, &(MyEnv.global_config_file), NULL, NULL, usage);
  for (; i < argc; i++)
    {
      char *cptr = argv[i];
      int bad_option;
      while (*cptr)
      {
        bad_option = 0;
        while (isspace (*cptr))
          cptr++;
        if (*cptr == '\0')
          break;
        if (isdigit (*cptr))
          {
            if (curr_desk < 2)
            {
              desks[curr_desk] = atoi (cptr);
              curr_desk++;
            }
            else
            bad_option = 1;
          }
        else if (*cptr == '-')
          {
            if (*(++cptr) == '-')
            {
              if (mystrncasecmp (cptr, "loadonly", 8) == 0)
                MyEnv.action = ACTION_LOADONLY;
              else if (mystrncasecmp (cptr, "kill", 4) == 0)
                MyEnv.action = ACTION_CLEANUP;
              else
                bad_option = 1;
            }
            else if (*(cptr + 1) == ' ' || *(cptr + 1) == '\0')
            {
              if (*cptr == 'l')
                MyEnv.action = ACTION_LOADONLY;
              else if (*cptr == 'k')
                MyEnv.action = ACTION_CLEANUP;
              else
                bad_option = 1;
              cptr++;
            }
            else
            bad_option = 1;
          }
        else
          bad_option = 1;

        if (bad_option)
          {
            fprintf (stderr, "\n%s: unknown option %s!", MyName, cptr);
            usage ();
          }
        while (!isspace (*cptr) && *cptr != '\0')
          cptr++;
      }
    }

  if (desks[1] >= desks[0])
    {
      MyEnv.desk1 = desks[0];
      MyEnv.desk2 = desks[1];
    }
  else
    {
      MyEnv.desk1 = desks[1];
      MyEnv.desk2 = desks[0];
    }
  /* Dead pipe == dead AfterStep */
  signal (SIGPIPE, DeadPipe);
  signal (SIGQUIT, DeadPipe);
  set_signal_handler (SIGSEGV);
  signal (SIGTERM, DeadPipe);
  signal (SIGKILL, DeadPipe);

  LOG2 ("\n%s connecting to X ...", MyName)
    Pipes.x_fd = ConnectX (ASDefaultScr, display_name, 0);
  InitAtoms (dpy, Atoms);
  /* enable root pixmap property setting */
  SetRootPixmapPropertyID (Atoms[ROOTPIXMAP_ATOM].atom);

  if (MyEnv.action == ACTION_DEFAULT)
    Pipes.fd[0] = Pipes.fd[1] = ConnectAfterStep (M_NEW_DESK | M_NEW_BACKGROUND, 0);

  LOG2 ("\n%s is parsing Options ...", MyName)
    if (MyEnv.action != ACTION_CLEANUP)
    {
      LoadBaseConfig (MyEnv.global_config_file, GetBaseOptions);
      LoadConfig (MyEnv.global_config_file, ASETROOT_CONFIG, GetOptions);
    }

  LOG2 ("\n%s starting The Loop ...", MyName)
    if (MyEnv.action == ACTION_LOADONLY)
    {
      XSetCloseDownMode (dpy, RetainPermanent);
      if (GetRootPixmap (Atoms[ROOTPIXMAP_ATOM].atom) == None)
      BackgroundSetForDesk (&DesksArray, (MyEnv.desk1 >= 0) ? MyEnv.desk1 : 0);
      ShowAsStarted ();
      DeadPipe (0);
    }
  else if (MyEnv.action == ACTION_CLEANUP)
    {
      Pixmap pix = None;
      GetBackgroundsProperty (&DesksArray, Atoms[BACKGROUND_ATOM].atom);
      if (DesksArray.desks_num > 0)
      {
        if ((pix = GetRootPixmap (Atoms[ROOTPIXMAP_ATOM].atom)) != None)
          {
            for (i = 0; i < DesksArray.desks_num; i++)
            if (DesksArray.desks[i].data_type == XA_PIXMAP && pix == DesksArray.desks[i].data.pixmap)
              {
                pix = None;
                break;
              }
            if (pix == None);
            XChangeProperty (dpy, Scr.Root, Atoms[ROOTPIXMAP_ATOM].atom, XA_PIXMAP, 32, PropModeReplace, (char *) &pix, 1);
          }
        XDeleteProperty (dpy, Scr.Root, Atoms[BACKGROUND_ATOM].atom);
        XFlush (dpy);
        sleep (1);
        /* now proceed to freeing all the pixmaps */
        DeleteMyBackgrounds (&DesksArray, 1);
      }
      ShowAsStarted ();
      XCloseDisplay (dpy);
    }
  else
    {
      XEvent event;
      /* strange things may happen if two different asetroots are servicing
         same range of desks. but to reduce risks - we add this code : */
      Scr.CurrentDesk = (MyEnv.desk1 >= 0) ? MyEnv.desk1 : 0;
      if (GetRootPixmap (Atoms[ROOTPIXMAP_ATOM].atom) == None)
      BackgroundSetForDesk (&DesksArray, Scr.CurrentDesk);

      ShowAsStarted ();
      while (1)
      if (My_XNextEvent (dpy, Pipes.x_fd, Pipes.fd[1], process_message, &event))
        if (event.xproperty.atom == Atoms[BACKGROUND_ATOM].atom)
          {
            ASDeskBackArray current =
            {NULL, 0};
            ASDeskBack *back;
            GetBackgroundsProperty (&current, Atoms[BACKGROUND_ATOM].atom);
            for (i = 0; i < DesksArray.desks_num; i++)
            if ((back = FindDeskBack (&current, DesksArray.desks[i].desk)) != NULL)
              DesksArray.desks[i] = *back;
            FreeDeskBackArray (&current, FALSE);
          }
    }

  return 0;
}

/***********************************************************************
 *
 *   Procedure:
 *   Process message - examines packet types, and takes appropriate action
 *
 ***********************************************************************/
void
process_message (unsigned long type, unsigned long *body)
{
  unsigned long *body_to_use = NULL;
  LOG4 ("\n%s: received AfterStep message #%ld, body[0]=%lu", MyName, type, body[0])

    while (type == M_NEW_DESK)
    {
      ASMessage *next_msg;
      if ((next_msg = CheckASMessage (Pipes.fd[1], 0)) == NULL)
      break;
      type = next_msg->header[1];
      LOG4 ("\n%s: received AfterStep message #%ld, body[0]=%lu", MyName, type, next_msg->body[0])
      if (type != M_NEW_DESK)
      list_new_desk ((body_to_use) ? body_to_use : body);
      if (body_to_use)
      free (body_to_use);
      body_to_use = next_msg->body;
      free (next_msg);
    }
  if (body_to_use == NULL)
    body_to_use = body;

  switch (type)
    {
    case M_NEW_DESK:
      list_new_desk (body);
      break;
    case M_NEW_BACKGROUND:
      list_new_background (body);
      break;
    default:
      list_unknown (body);
      break;
    }
}


/***********************************************************************
 *
 *   Procedure:
 *   SIGPIPE handler - SIGPIPE means afterstep is dying
 *
 ***********************************************************************/
void
DeadPipe (int nonsense)
{
/* here we must remove our backgrounds from backgrounds information list
   as they are no longer valid */
  ASDeskBackArray dummy =
  {NULL, 0}, *saved;
  int i = 0;

  /* merely duplicating data, as we want to destroy old pixmaps,
     only after setting all X properties to None        */
  if (MyEnv.action == ACTION_DEFAULT)
    {
      saved = UpdateDeskBackArray (&dummy, &DesksArray);
      for (i = 0; i < DesksArray.desks_num; i++)
      {
        if (DesksArray.desks[i].data_type == XA_PIXMAP ||
            DesksArray.desks[i].MyStyle != None)
          DesksArray.desks[i].data.pixmap = None;
      }
      UpdateBackgroundProperty ();
      free (DesksArray.desks);
      FreeDeskBackArray (saved, TRUE);
      free (saved);
    }
  else
    {
      FreeDeskBackArray (&DesksArray, FALSE);
    }

#ifdef DEBUG_ALLOCS
/* normally, we let the system clean up, but when auditing time comes
 * around, it's best to have the books in order... */
  {
    free (pixmapPath);
    {
      GC foreGC, backGC, reliefGC, shadowGC;

      mystyle_get_global_gcs (mystyle_first, &foreGC, &backGC, &reliefGC, &shadowGC);
      mystyle_destroy_all();
      XFreeGC (dpy, foreGC);
      XFreeGC (dpy, backGC);
      XFreeGC (dpy, reliefGC);
      XFreeGC (dpy, shadowGC);
    }
    print_unfreed_mem ();

  }

#endif /* DEBUG_ALLOCS */

  XFlush (dpy);
  XCloseDisplay (dpy);
  exit (0);
}

/***********************************************************************
 *
 *   Procedure:
 *   list_new_desk - displays packet contents to stderr
 *
 ***********************************************************************/

void
list_new_desk (unsigned long *body)
{
  LOG2 ("\n%s:list_new_desk():\tDone!", MyName)
    if (body[0] != 10000)
    {
      Scr.CurrentDesk = body[0];
      if (IsDeskInRange (Scr.CurrentDesk))
      BackgroundSetForDesk (&DesksArray, Scr.CurrentDesk);
    }
}

/***********************************************************************
 *
 *   Procedure:
 *         list_new_background - reread config file & reconfigure on fly
 *
 ***********************************************************************/
void
list_new_background (unsigned long *body)
{
/* need to add code here to reread config file */
  ASDeskBackArray dummy =
  {NULL, 0}, *saved;

  /* merely duplicating data, as we want to destroy old pixmaps,
     only after setting all X properties to updated data        */
  saved = UpdateDeskBackArray (&dummy, &DesksArray);
  /* that will also set X property for backgrounds info for us */
  LoadConfig (MyEnv.global_config_file, ASETROOT_CONFIG, GetOptions);
  /* informing everybody about new root background */
#ifdef DEBUG_ASETROOT
  fprintf (stderr, "setting new desk background to: \n");
  PrintDeskBackArray (&DesksArray);
#endif
  BackgroundSetForDesk (&DesksArray, Scr.CurrentDesk);

  if (saved)
    {
      long saved_curr_desk = Scr.CurrentDesk;
      /* we don't want to reset root pixmap ID property, don't we ? */
      Scr.CurrentDesk = 10000;
      FreeDeskBackArray (saved, TRUE);
      Scr.CurrentDesk = saved_curr_desk;
      free (saved);
    }
}

/***********************************************************************
 *
 *   Procedure:
 *   list_unknow - handles an unrecognized packet.
 *
 ***********************************************************************/
void
list_unknown (unsigned long *body)
{
  /*   fprintf(stderr,"Unknown packet type\n"); */
}

/******************************************************************/
/* configuration reading stuff                                    */
/******************************************************************/
int
IsDeskInRange (long desk)
{
  return ((MyEnv.desk1 < 0 || desk >= MyEnv.desk1) &&
        (MyEnv.desk2 < 0 || desk <= MyEnv.desk2));
}

void
DeleteMyBackgrounds (ASDeskBackArray * backs, int verbose)
{
  Pixmap *deleted_pixmaps;
  register int i, k;
  if (backs->desks_num <= 0)
    return;
  deleted_pixmaps = (Pixmap *) safemalloc (backs->desks_num * sizeof (Pixmap));
  for (i = 0; i < backs->desks_num; i++)
    deleted_pixmaps[i] = None;

  if (verbose)
    fprintf (stderr, "\n");
  for (i = 0; i < backs->desks_num; i++)
    if (IsDeskInRange (backs->desks[i].desk) &&
      IsPurePixmap (&(backs->desks[i])))
      {
      for (k = 0; k < backs->desks_num; k++)
        if (deleted_pixmaps[k] == backs->desks[i].data.pixmap)
          {
            backs->desks[i].data.pixmap = None;
            break;
          }
      if (backs->desks[i].data.pixmap != None)
        {
          int skip = 0;
          if (ValidatePixmap (backs->desks[i].data.pixmap, True, False, NULL, NULL) != None)
            XFreePixmap (dpy, backs->desks[i].data.pixmap);
          else
            {
            skip = 1;
            if (verbose)
              fprintf (stderr, "%s: invalid root background pixmap %ld from the desk #%ld - skipping.\n",
              MyName, backs->desks[i].data.pixmap, backs->desks[i].desk);
            }

          for (k = 0; k < backs->desks_num; k++)
            if (deleted_pixmaps[k] == None)
            {
              deleted_pixmaps[k] = backs->desks[i].data.pixmap;
              break;
            }
          if (verbose && !skip)
            fprintf (stderr, "%s: Freed root background pixmap %ld from the desk #%ld.\n",
             MyName, backs->desks[i].data.pixmap, backs->desks[i].desk);
          XFlush (dpy);
          backs->desks[i].data.pixmap = None;
        }
      else if (verbose)
        fprintf (stderr, "%s: already freed root background pixmap %ld from the desk #%ld.\n",
               MyName, deleted_pixmaps[k], backs->desks[i].desk);
      }
  free (deleted_pixmaps);
}

void
UpdateBackgroundProperty ()
{
  ASDeskBackArray current =
  {NULL, 0};
  ASDeskBackArray *updated;
/* making sure that only one client at a time updates backgrounds property */
  XGrabServer (dpy);
  GetBackgroundsProperty (&current, Atoms[BACKGROUND_ATOM].atom);

  PrintDeskBackArray (&current);
  PrintDeskBackArray (&DesksArray);
  if (MyEnv.action == ACTION_LOADONLY)
    {                   /* we need to destroy all the backgrounds in our range */
      int i, k;
#if      1
      for (i = 0; i < current.desks_num; i++)
      if (IsDeskInRange (current.desks[i].desk) &&
          IsPurePixmap (&(current.desks[i])))
        {
          ASDeskBack *back;
          /* this background is about to be deleted -
             let's see if anyone else is using it too : */
          for (k = 0; k < current.desks_num; k++)
            if (!IsDeskInRange (current.desks[k].desk) &&
              IsPurePixmap (&(current.desks[k])) &&
             current.desks[k].data.pixmap == current.desks[i].data.pixmap)
            {
              back = FindDeskBack (&DesksArray, current.desks[i].desk);
              if (back)
                {
                  current.desks[k].data = back->data;
                  current.desks[k].data_type = back->data_type;
                  current.desks[k].MyStyle = back->MyStyle;;
                }
            }
        }
#endif
      DeleteMyBackgrounds (&current, 0);

    }

  if ((updated = UpdateDeskBackArray (&current, &DesksArray)) != NULL)
    {
      PrintDeskBackArray (updated);
      SetBackgroundsProperty (updated, Atoms[BACKGROUND_ATOM].atom);
      FreeDeskBackArray (updated, FALSE);
      free (updated);
      XFlush (dpy);
    }
  if (current.desks)
    free (current.desks);
  XUngrabServer (dpy);
}



void
DuplicateDeskBack (ASDeskBack * trg, ASDeskBack * src)
{
  trg->data_type = src->data_type;
  trg->data = src->data;
  trg->MyStyle = src->MyStyle;
}

/* just a stub so far */
Pixmap
DoTransformPixmap (ASImage *src, MyBackgroundConfig * back)
{
      Pixmap trg = None;
    unsigned int width, height;
      int x = 0, y = 0;
      ARGB32 tint = TINT_LEAVE_SAME ;
      ARGB32 pad_color = 0 ;
      unsigned int screen_width = Scr.MyDisplayWidth;
    unsigned int screen_height = Scr.MyDisplayHeight;
      ASImage *work_im = src ;

      if (src == NULL)
            return None;

      width = src->width ;
      height = src->height ;
    /* cut and tint */
    if (back->flags & BGFLAG_PAD)
    {
            if( parse_argb_color( back->pad, &pad_color ) == back->pad )
                  pad_color = 0 ;
    }
    if (back->flags & BGFLAG_TINT)
    {
            if( parse_argb_color( back->tint, &tint ) == back->tint )
                  tint = TINT_LEAVE_SAME;
    }

    if (back->flags & BGFLAG_CUT)
    {
      x = (back->cut.x < width) ? back->cut.x : 0;
      y = (back->cut.y < height) ? back->cut.y : 0;
      if (back->cut.width >= width - x || back->cut.width <= 0)
                  width -= x;
        else
                  width = back->cut.width;
        if (back->cut.height >= height - x || back->cut.height <= 0)
                  height -= y;
          else
                  height = back->cut.height;
    }
    if (back->flags & BGFLAG_CUT || tint != TINT_LEAVE_SAME)
    {
            ASImage *tiled_im = tile_asimage( Scr.asv, work_im,
                                              x, y, width, height, tint,
                                              ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT );
            if( tiled_im )
            {
                  if( work_im != src )
                        destroy_asimage( &work_im );
                  work_im = tiled_im ;
            }
    }

    if( Scr.xinerama_screens && Scr.xinerama_screens_num > 1 )
      {
          register int i = Scr.xinerama_screens_num ;
            while( --i > 0 )
                  if( Scr.xinerama_screens[i].x == 0 && Scr.xinerama_screens[i].y == 0 )
                      break ;
          screen_width = Scr.xinerama_screens[i].width ;
          screen_height = Scr.xinerama_screens[i].height ;
    }

      /* scale */
    if (back->flags & BGFLAG_SCALE)
    {
            ASImage *scaled_im ;

          if (back->scale.width > 0)
                  width = back->scale.width;
          if (back->scale.height > 0)
                  height = back->scale.height;
        if (back->scale.width <= 0 && back->scale.height <= 0)
            {
                width = screen_width;
                height = screen_height;
            }

            scaled_im = scale_asimage( Scr.asv, work_im, width, height,
                                       ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT );
            if( scaled_im )
            {
                  if( work_im != src )
                        destroy_asimage( &work_im );
                  work_im = scaled_im ;
            }
    }
    /* align + pad   */
      if (back->flags & BGFLAG_PAD)
    {
          unsigned int old_width = width, old_height = height;
            ASImage *padded_im ;

      if (back->flags & BGFLAG_PAD_HOR)
                  width = screen_width;
          if (back->flags & BGFLAG_PAD_VERT)
                  height = screen_height;
        if (!(back->flags & BGFLAG_PAD_HOR) && !(back->flags & BGFLAG_PAD_VERT))
            {
                width = screen_width;
                height = screen_height;
            }

          x = (back->flags & BGFLAG_ALIGN_RIGHT) ? width - old_width : 0;
        y = (back->flags & BGFLAG_ALIGN_BOTTOM) ? height - old_height : 0;
          if ( (back->flags & BGFLAG_ALIGN) &&
                !(back->flags & BGFLAG_ALIGN_BOTTOM) &&
                  !(back->flags & BGFLAG_ALIGN_RIGHT))
            {
                x = (width - old_width) / 2;
                y = (height - old_height) / 2;
            }

            padded_im = pad_asimage( Scr.asv, work_im, x, y, width, height,
                                                 pad_color,
                                     ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT );
            if( padded_im )
            {
                  if( work_im != src )
                        destroy_asimage( &work_im );
                  work_im = padded_im ;
            }
    }

      trg = asimage2pixmap( Scr.asv, Scr.Root, work_im, NULL, False );
      if( work_im != src )
            destroy_asimage( &work_im );
      return trg;
}

/* loading background information and converting it into useble form */
void
ProcessNewBackground (MyBackgroundConfig * back, ASDeskBack * desk)
{
    desk->MyStyle = None;
      desk->data.pixmap = None;
    desk->data_type = None;
      if (back->data == NULL)
          return;
    if (back->data[0] == '\0')
          return;

      LOG3 ("\n Ok to process new back[%s] for desk %d", back->data, desk->desk)
    /* process data based on flags */
      /* if it is image - then load image and set data_type = pixmap and Pixmap */
    /* if it is image of wrong format - go to command */
      /* if it is Style - then set MyStyle to atom of MyStyle's name and data = 0 */
    /* if it is command - then build complete command line and create XAtom */
    if (back->flags & BGFLAG_FILE)
    {
            ASImage *im = get_asimage( ImMan, back->data, 0xFFFFFFFF, 100 );
      if (im)
            {
                  desk->data_type = XA_PIXMAP;
                  /* do all the transformations if it is the pixmap */
                  desk->data.pixmap = DoTransformPixmap (im, back);
                  release_asimage(im);
                  return;
            }
    }
    if (back->flags & BGFLAG_MYSTYLE)
    {                   /* try to find style */
          if ((desk->MyStyle = XInternAtom (dpy, back->data, True)) == None)
                  fprintf (stderr, "%s: cannot use undefined style [%s] for background of desk #%ld!", MyName, back->data, desk->desk);
    }else
      {    /* command should be executed to set background */
          char *full_cmd, *prefix;
      int pref_len;

      prefix = mystrdup (XIMAGELOADER);
      if (!(back->flags & BGFLAG_FILE))
            {/* we should get all command options supplied so cut prefix to
                only a prog name */
             /* assuming we don't have spaces here in path to prog itself - only option
                  separator spaces */
                char *ptr = strchr (prefix, ' ');
                  if (ptr)
                *ptr = '\0';
            }
          pref_len = strlen (prefix);
        full_cmd = (char *) safemalloc (pref_len + 1 + strlen (back->data) + 1);
          strcpy (full_cmd, prefix);
      full_cmd[pref_len] = ' ';
        strcpy (&(full_cmd[pref_len + 1]), back->data);
          desk->data.atom = XInternAtom (dpy, full_cmd, False);
          free (full_cmd);
      free (prefix);
    }
}

/*****************************************************************************
 *
 * This routine is responsible for reading and parsing the config file
 *
 ****************************************************************************/

void
GetOptions (const char *filename)
{
#ifdef DO_CLOCKING
  clock_t started = clock ();
#endif
  ASetRootConfig *config;
  int i;

  struct BackCrossref
    {
      MyBackgroundConfig *back;
      ASDeskBack *desk;
    }
   *back_crossref;

  int backs_num = 0, backs_filled = 0;
  MyBackgroundConfig *curr_back;
  DeskBackConfig *curr_desk;

  config = ParseASetRootOptions (filename, MyName);
  if (!config)
    exit (0);                 /* something terrible has happend */
#ifdef DO_CLOCKING
  fprintf (stderr, "\n Config parsing time (clocks): %lu\n", clock () - started);
#endif

  /* processing all mystyles first as we will need them in place in order
     to use backgrounds */
  /* reading global styles first */
  if (MyEnv.action == ACTION_DEFAULT)
    {
      mystyle_get_property (dpy, Scr.Root, Atoms[MYSTYLE_ATOM].atom, Atoms[MYSTYLE_ATOM].type);
      if (config->style_defs)
      ProcessMyStyleDefinitions (&(config->style_defs), pixmapPath);
    }

  /* now lets convert config into the list of desks and list
     ASDeskBack's */
  /* first let's see how many backgrounds we have defined max */
  for (curr_back = config->my_backs; curr_back;
       curr_back = curr_back->next)
    backs_num++;
  back_crossref = (struct BackCrossref *)
    safemalloc (sizeof (struct BackCrossref) * backs_num);
  for (i = 0; i < backs_num; i++)
    back_crossref[i].back = NULL;
  /* now let's count our desks */
  DesksArray.desks_num = 0;   /* just in case */
  for (curr_desk = config->my_desks; curr_desk;
       curr_desk = curr_desk->next)
    if (IsDeskInRange (curr_desk->desk) &&
      curr_desk->back != NULL)
      DesksArray.desks_num++;
  if (DesksArray.desks)
    free (DesksArray.desks);
  DesksArray.desks = (ASDeskBack *) safemalloc (sizeof (ASDeskBack) * DesksArray.desks_num);

  /* now we are ready to do the real thing */
  i = 0;
  for (curr_desk = config->my_desks; curr_desk;
       curr_desk = curr_desk->next)
    {
      int k;
      LOG2 ("\n processing desk %d", curr_desk->desk)
      if (!IsDeskInRange (curr_desk->desk) ||         /* out of range ! */
          curr_desk->back == NULL)
      continue;
      /* Now  let's add record to DesksArray and do all the neccessary
         image preparation */
      DesksArray.desks[i].desk = curr_desk->desk;
      /* first check if we already have this background loaded */
      for (k = 0; k < backs_filled; k++)
      if (back_crossref[k].back == curr_desk->back)
        break;
      if (k < backs_filled && back_crossref[k].desk)
      {                 /* just copy stuff over */
        DuplicateDeskBack (&(DesksArray.desks[i]), back_crossref[k].desk);
      }
      else
      {                 /* process new background */
        ProcessNewBackground (curr_desk->back, &(DesksArray.desks[i]));
        back_crossref[k].back = curr_desk->back;
        back_crossref[k].desk = &(DesksArray.desks[i]);
        if (k == backs_filled)
          backs_filled++;
      }
      if (MyEnv.action == ACTION_LOADONLY)
      {
        if (IsPurePixmap (&(DesksArray.desks[i])))
          fprintf (stderr, "%s: loaded root background for desk# %d (pixmap   id is %ld).\n", MyName, curr_desk->desk, DesksArray.desks[i].data.pixmap);
        else if (DesksArray.desks[i].MyStyle != None)
          fprintf (stderr, "%s: loaded root background for desk# %d (MyStyle  id is %ld).\n", MyName, curr_desk->desk, DesksArray.desks[i].MyStyle);
        else
          fprintf (stderr, "%s: loaded root background for desk# %d (resource id is %ld).\n", MyName, curr_desk->desk, DesksArray.desks[i].data.atom);

      }
      LOG3 ("\n desk #%d aded %d", i, DesksArray.desks[i]);
      i++;
    }
  free (back_crossref);
#ifdef DO_CLOCKING
  fprintf (stderr, "\n Background processing time (clocks): %lu\n", clock () - started);
#endif
  /* letting everybody know about what will be used as backgrounds */
  UpdateBackgroundProperty ();

  /* uff, here we are at the end at last - let's clean the mess now */
  DestroyASetRootConfig (config);
#if defined(DEBUG_ASETROOT) && defined(DEBUG_ALLOCS)
  fprintf (stderr, "\n Unfreed memory at the end of startup phase:\n");
  print_unfreed_mem ();
#endif
#ifdef DO_CLOCKING
  fprintf (stderr, "\n Total startup time (clocks): %lu\n", clock () - started);
#endif
}


/*****************************************************************************
 *
 * This routine is responsible for reading and parsing the base file
 *
 ****************************************************************************/
void
GetBaseOptions (const char *filename)
{
#ifdef DO_CLOCKING
  clock_t started = clock ();
#endif
  BaseConfig *config = ParseBaseOptions (filename, MyName);

  if (!config)
    exit (0);                 /* something terrible has happend */

  pixmapPath = config->pixmap_path;
  config->pixmap_path = NULL; /* setting it to NULL so it would not be
                           deallocated by DestroyBaseConfig */
  DestroyBaseConfig (config);
  
  if( ImMan ) 
        destroy_image_manager( ImMan, False );
  ImMan = create_image_manager( NULL, 2.2, pixmapPath, NULL );

#ifdef DO_CLOCKING
  fprintf (stderr, "\n Base Config parsing time (clocks): %lu\n", clock () - started);
#endif

}

Generated by  Doxygen 1.6.0   Back to index