Logo Search packages:      
Sourcecode: matchbox-panel version File versions  Download package

mb-applet-menu-launcher.c

/*
   mb-applet-menu-launcher - a small application launcher

   Copyright 2002 Matthew Allum

   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, 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.
*/

/*
  TODO
  o fix crash on menu's bigger than display.
  o add logout / lock buttons on root menu.
     - add use_gpe defines for this !
*/

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

#ifdef USE_DNOTIFY
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>

#include <libmb/mb.h>


#ifdef USE_LIBSN
#define SN_API_NOT_YET_FROZEN 1
#include <libsn/sn.h>
#endif

#ifndef MB_HAVE_PNG
#include <setjmp.h>
#endif

00055 typedef struct _app
{
  MBTrayApp     *tray_app; 
  MBMenu        *mbmenu;
  MBPixbuf      *pb;

  MBPixbufImage *img_tray;
  MBPixbufImage *img_tray_scaled;
  MBPixbufImage *img_tray_active;
  MBPixbufImage *img_tray_active_scaled;

  Atom           mbtheme_atom;
  Atom           mbcommand_atom;

  char          *theme_name;
  Bool           button_is_down;

#ifdef USE_LIBSN
  SnDisplay  *sn_display;
#endif
   
} AppData;

AppData     *app_data;

MBMenuMenu  *root;
Bool         Update_Pending  = False;
jmp_buf      Jbuf;
MBMenuMenu  *active[10];
int          MenuWasActive   = False;

Bool         WantDebianMenus = False;
volatile Bool WantReload     = False;


static void reap_children (int signum);
static void fork_exec (char *cmd);
static void usage ();
static int  parse_menu_file (char *data);
static void build_menu (void);
static void catch_sigsegv (int sig);
static void load_icon(void);

#ifdef USE_LIBSN
static void sn_exec(char* name, char* bin_name, char *desc);
#endif

#ifdef USE_DNOTIFY
static void reload_menu(int signum, siginfo_t *siginfo, void *data);
#endif

#ifdef MB_HAVE_PNG
#define TRAY_IMG "mbmenu.png"
#define TRAY_IMG_ACTIVE "mbmenu-active.png"
#else
#define TRAY_IMG "mbmenu.xpm"
#define TRAY_IMG_ACTIVE "mbmenu-active.xpm"
#endif

#define SINGLE_INSTANCE 1
#define STARTUP_NOTIFY  2

#define UP   0
#define DOWN 1

#define MENUDIR "/usr/lib/menu"

#define MBMAX(x,y) ((x>y)?(x):(y))

#define NEW(OBJ) ((OBJ *)(malloc(sizeof(OBJ))))

#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\\' \
                          || (c) == '\t' || (c)=='\n' || (c)=='?')

#ifdef DEBUG
#define DBG(txt, args... ) fprintf(stderr, "DEBUG: " txt , ##args )
#else
#define DBG(txt, args... ) /* nothing */
#endif

static void usage()
{
  printf("usage: mbmenu [options ....]\n"
        "Where options are\n"
        "  -display <display> Display to connect to\n"
        "\nAlso set MB_USE_DEB_MENUS env var to enable parsing /usr/lib/menu"
        "\n"

        );
   exit(1);
}

static void catch_sigsegv(int sig)
{
   DBG("ouch\n");
   signal(SIGSEGV, SIG_DFL);
   longjmp(Jbuf, 1);

}

static void reap_children(int signum)
{
    pid_t pid;

    do {
      pid = waitpid(-1, NULL, WNOHANG);
    } while (pid > 0);
}

#ifdef USE_LIBSN

static void 
sn_exec(char* name, char* bin_name, char *desc)
{
  SnLauncherContext *context;
  pid_t child_pid = 0;

  context = sn_launcher_context_new (app_data->sn_display, 
                             mb_tray_app_xscreen(app_data->tray_app));
  
  if (name)     sn_launcher_context_set_name (context, name);
  if (desc)     sn_launcher_context_set_description (context, desc);
  if (bin_name) sn_launcher_context_set_binary_name (context, bin_name);
  
  sn_launcher_context_initiate (context, "mbmenu launch", bin_name,
                        CurrentTime);

  switch ((child_pid = fork ()))
    {
    case -1:
      fprintf (stderr, "Fork failed\n" );
      break;
    case 0:
      sn_launcher_context_setup_child_process (context);
      mb_exec(bin_name);
      fprintf (stderr, "mb-applet-menu-launcher: Failed to exec %s \n", bin_name);
      _exit (1);
      break;
    }
}

#endif

static void fork_exec(char *cmd)
{
    pid_t pid;
    
    switch (pid = fork()) 
      {
      case 0:
      mb_exec(cmd);
      /* execlp("/bin/sh", "sh", "-c", cmd, NULL); */
      fprintf(stderr, "mb-applet-menu-launcher: exec of '%s' failed, cleaning up child\n", cmd);
      exit(1);
      case -1:
      fprintf(stderr, "mb-applet-menu-launcher: can't fork '%s'\n", cmd); break;
      }
}

#ifdef USE_LIBSN
static
void menu_clicked_sn_cb(MBMenuItem *item)
{
  sn_exec(item->title, item->info, item->info);
}

static
void menu_clicked_si_cb(MBMenuItem *item)
{
  Window win_found;

  win_found = mb_single_instance_get_window(mb_tray_app_xdisplay(app_data->tray_app), item->info);

  if (win_found != None)
    {
      mb_util_window_activate(mb_tray_app_xdisplay(app_data->tray_app), win_found);
    }
  else menu_clicked_sn_cb(item);
}
#endif

static
void menu_clicked_cb(MBMenuItem *item)
{
  fork_exec(item->info);
}

static int
parse_menu_file(char *data)
{
   char *p, *key, *val;

   char *tmp_title;
   char *tmp_section;
   char *tmp_cmd;
   char *tmp_icon;
   char *tmp_needs;

   signal(SIGSEGV, catch_sigsegv);
   if (setjmp(Jbuf)) return 0;  /* catch possible parse segfualt  */

   tmp_title = NULL;
   tmp_section = NULL;
   tmp_cmd = NULL;
   tmp_icon = NULL;
   tmp_needs = NULL;
   p = data;
   
   if (*p != '?') return 0;   /* check is an actual menu entry  */
   
   while(*(++p) != ':'); *p = ' '; /* skip to first entry */
   
   while(*p != '\0')
   {
      if ((!IS_WHITESPACE(*p))
        || (IS_WHITESPACE(*p) && *(p+1) != '\0'
            && (!IS_WHITESPACE(*(p+1)))))
      {
       /* process key=pair */
         char *lc = " \t\n\\";
       char *sc = "\"";
       char *tc = lc; 
         if (IS_WHITESPACE(*p)) p++;
       key = p;
       while(*p != '=') p++; *p = '\0';
       DBG("\tkey %s ", key);
         if (*(++p) == '"') { p++; tc = sc; } /* skip "'s */
       val = p;
       while(index(tc,*p) == NULL)
       {
          if (*p == '\\' && *(p+1) == '"') p++;  /* skip \" */
          p++;
       } *p = '\0';
       DBG("value %s \n", val);

       if(!strcmp(key,"title"))        { tmp_title = val;  }
       else if(!strcmp(key,"section")) { tmp_section = val; }
       else if(!strcmp(key,"command")) { tmp_cmd = val; }
       else if(!strcmp(key,"icon"))    { tmp_icon = val; }
       else if(!strcmp(key,"icon16"))    { tmp_icon = val; }
       else if(!strcmp(key,"icon32"))    { tmp_icon = val; }
       else if(!strcmp(key,"icon48"))    { tmp_icon = val; }
       else if(!strcmp(key,"needs"))    { tmp_needs = val; }

      }
      p++;

      if (tmp_section && (*p == '?' || *p == '\0'))
      {
       if ( (!strcmp(tmp_needs,"x11"))
            || (!strcmp(tmp_needs,"X11"))
            || (!strcmp(tmp_needs,"text"))
            || tmp_needs == NULL )
       {
        MBMenuMenu *m = NULL;

         char *tmpstr = 
           (char *)malloc(sizeof(char)*(strlen(tmp_section)+
                                strlen(tmp_title)+12));
         sprintf(tmpstr, "Other/%s", tmp_section);

         m = mb_menu_add_path(app_data->mbmenu, tmpstr, NULL, 0);
         mb_menu_add_item_to_menu(app_data->mbmenu, m, tmp_title, 
                               tmp_icon, tmp_cmd, 
                            menu_clicked_cb, NULL, 0); 
       }
      }
   }   
       /* reset all */
      tmp_title = NULL;
      tmp_section = NULL;
      tmp_cmd = NULL;
      tmp_icon = NULL;
      
      /* new menu entry */
      
      if ( *p == '?')
       {
         DBG("new entry, igonoring package(foo) data\n");
         while(*(++p) != ':');
         *p = ' ';
       }
      
   
   signal(SIGSEGV, SIG_DFL);
   return 1;
}

#ifdef USE_DNOTIFY
static
void really_reload_menu(int signum)
{
  DBG("Really Reload menu callback\n");

  WantReload = True;

}


static 
void reload_menu(int signum, siginfo_t *siginfo, void *data)
{
  DBG("Reload menu callback\n");

  /* To avoid the barrage of signals dnotify likes to send when
   * a file is updated we set an alarm.
   *
   */
  signal (SIGALRM, really_reload_menu);
  alarm(3);

}
#endif

static void
build_menu(void)
{

#define APP_PATHS_N 4

  struct menu_lookup_t {
    char       *match_str;
    MBMenuMenu *item;
  };

  int i = 0, j = 0;
  DIR *dp;
  struct dirent *dir_entry;
  struct stat stat_info;

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

  char orig_wd[MAXPATHLEN];

  char dirs[2][256] = { MENUDIR };
  FILE *fp;
  char *buf;
  int len;
  MBMenuMenu *menu_panel;
  char *tmp_path = NULL, *tmp_path2 = NULL ;

  char vfolder_path_root[512];
  char vfolder_path[512];
  MBDotDesktop            *dd;
  MBDotDesktopFolders     *ddfolders;
  MBDotDesktopFolderEntry *ddentry;
  char                    *root_match_str;

  /* List of paths to check for .desktop files */
  char                     app_paths[APP_PATHS_N][256];
  Bool got_root_items        = False;
  Bool had_action_sepearator = False;

  struct menu_lookup_t *menu_lookup = NULL;

  snprintf( vfolder_path_root, 512, "%s/.matchbox/vfolders/Root.directory", getenv("HOME"));
  snprintf( vfolder_path, 512, "%s/.matchbox/vfolders", getenv("HOME"));

  if (stat(vfolder_path_root, &stat_info))
    {
      snprintf(vfolder_path_root, 512, PKGDATADIR "/vfolders/Root.directory");
      snprintf(vfolder_path, 512, PKGDATADIR "/vfolders" );
    }
  
  dd = mb_dotdesktop_new_from_file(vfolder_path_root);

  if (!dd)  
    { 
      fprintf( stderr, 
             "mb-applet-menu-launcher: cant open " PKGDATADIR "/vfolders/Root.desktop\n"
             "                         Did you install matchbox-common ?" ); 
      exit(1); 
    }

  root_match_str = mb_dotdesktop_get(dd, "Match");

  /* Now grab the vfolders */
  ddfolders = mb_dot_desktop_folders_new(vfolder_path);

  menu_lookup = malloc(sizeof(struct menu_lookup_t)*mb_dot_desktop_folders_get_cnt(ddfolders));

  mb_dot_desktop_folders_enumerate(ddfolders, ddentry)
    {
      char *icon_path = NULL;
      char *folder_name = NULL;

      /* Check Name is valid for entry */
      if ((folder_name = mb_dot_desktop_folder_entry_get_name(ddentry)) == NULL)
      continue;

      if (mb_dot_desktop_folder_entry_get_icon(ddentry))
      icon_path = mb_dot_desktop_icon_get_full_path (app_data->theme_name, 
                                           16, 
                                           mb_dot_desktop_folder_entry_get_icon(ddentry) );

      menu_lookup[i].item = mb_menu_add_path(app_data->mbmenu, 
                                   folder_name,
                                   icon_path, MBMENU_NO_SORT );

      menu_lookup[i].match_str = mb_dot_desktop_folder_entry_get_match(ddentry);
      i++;

    }

  menu_panel = mb_menu_add_path(app_data->mbmenu, "Utilities/Panel" , NULL, MBMENU_NO_SORT );


  tmp_path = mb_dot_desktop_icon_get_full_path (app_data->theme_name, 
                                    16, 
                                    "mbfolder.png" );

  tmp_path2 = mb_dot_desktop_icon_get_full_path (app_data->theme_name, 
                                    16, 
                                    "mbnoapp.png" );

  mb_menu_set_default_icons(app_data->mbmenu, tmp_path, tmp_path2);

  if (tmp_path) free(tmp_path);
  if (tmp_path2) free(tmp_path2);

  if (getcwd(orig_wd, MAXPATHLEN) == (char *)NULL)
    {
      fprintf(stderr, "mb-applet-menu-launcher: cant get current directory\n");
      exit(0);
    }

  snprintf(app_paths[0], 256, "%s/applications", DATADIR);  
  snprintf(app_paths[1], 256, "/usr/share/applications");
  snprintf(app_paths[2], 256, "/usr/local/share/applications");
  snprintf(app_paths[3], 256, "%s/.applications", getenv("HOME"));

  
  for (j = 0; j < APP_PATHS_N; j++)
    {

      /* Dont reread the prefix path if matches */
      if (j > 0 && !strcmp(app_paths[0], app_paths[j]))
      continue;

      if ((dp = opendir(app_paths[j])) == NULL)
      {
        fprintf(stderr, "mb-applet-menu-launcher: failed to open %s\n", 
              app_paths[j]);
        continue;
      }
      
      chdir(app_paths[j]);

      while((dir_entry = readdir(dp)) != NULL)
      {
        if (strcmp(dir_entry->d_name+strlen(dir_entry->d_name)-8,".desktop"))
          continue;
        
        lstat(dir_entry->d_name, &stat_info);
        if (!(S_ISDIR(stat_info.st_mode)))
          {
            MBDotDesktop *dd;
            int flags = 0;
            
            dd = mb_dotdesktop_new_from_file(dir_entry->d_name);
            if (dd)
            {
              char *png_path = NULL;
              MBMenuActivateCB activate_callback = NULL;
              
              if (mb_dotdesktop_get(dd, "Icon") 
                  && mb_dotdesktop_get(dd, "Name")
                  && mb_dotdesktop_get(dd, "Exec"))
                {
                  MBMenuMenu *m = NULL, *fallback = NULL;
                  char *category;
                  
                  png_path = mb_dot_desktop_icon_get_full_path(app_data->theme_name, 16, mb_dotdesktop_get(dd, "Icon"));
                  
                  category = mb_dotdesktop_get(dd, "Categories");
                  
                  if (png_path && category && strstr(category, "Action"))
                  {
                    m = app_data->mbmenu->rootmenu;

                    if (!had_action_sepearator)
                      {
                          mb_menu_add_seperator_to_menu(app_data->mbmenu,
                                                app_data->mbmenu->rootmenu, 
                                                MBMENU_NO_SORT);
                        had_action_sepearator = True;
                      }

                    flags = MBMENU_NO_SORT;
                  }
                  else
                  {
                    if (root_match_str)
                      {
                        if (!strcmp("fallback", root_match_str))
                        {
                          fallback = app_data->mbmenu->rootmenu;
                        }
                        else if (category 
                               && strstr(category, root_match_str))
                        {
                          m = app_data->mbmenu->rootmenu;
                        }
                      }
                    
                    if (m == NULL 
                        && category != NULL)
                      {
                        for (i=0; 
                           i<mb_dot_desktop_folders_get_cnt(ddfolders);
                           i++)
                        {
                          if (!strcmp(menu_lookup[i].match_str,
                                    "fallback"))
                            {
                              fallback = menu_lookup[i].item;
                            }
                          if (strstr(category, 
                                   menu_lookup[i].match_str))
                            {
                              m = menu_lookup[i].item;
                            }
                        }
                      }
                    
                    if (m == NULL) m = fallback;
                    
                  }
                  activate_callback = menu_clicked_cb;
#ifdef USE_LIBSN
                  
                  if (mb_dotdesktop_get(dd, "SingleInstance")
                    && !strcasecmp(mb_dotdesktop_get(dd, 
                                             "SingleInstance"),
                               "true"))
                  {
                    activate_callback = menu_clicked_si_cb;
                  }
                  else if (mb_dotdesktop_get(dd, "StartupNotify")
                         && !strcasecmp(mb_dotdesktop_get(dd, 
                                                "StartupNotify"),
                                    "true"))
                  {
                    activate_callback = menu_clicked_sn_cb;
                  }
#endif
                  if (mb_dotdesktop_get(dd, "Type") 
                    && !strcmp(mb_dotdesktop_get(dd, "Type"), 
                             "PanelApp"))
                  {
                    m = menu_panel;
                  }
                  
                  if (png_path && m)
                  {
                    
                    if (!flags && m == app_data->mbmenu->rootmenu)
                      {
                        if (got_root_items == False)
                        {
                          mb_menu_add_seperator_to_menu(app_data->mbmenu, 
                                                app_data->mbmenu->rootmenu, 
                                                MBMENU_PREPEND);
                          got_root_items = True;
                        }
                        
                        flags = MBMENU_PREPEND;
                      }
                    
                    mb_menu_add_item_to_menu(app_data->mbmenu, m, 
                                       mb_dotdesktop_get(dd, "Name"),
                                       png_path,
                                       mb_dotdesktop_get_exec(dd),
                                       activate_callback, 
                                       (void *)app_data, flags); 
                    /* mb_menu_add_seperator_to_menu(app_data-> mbmenu, m); */
                    
                    free(png_path);
                  }
                }
              else fprintf(stderr, 
                         "mb-applet-menu-launcher: %s has no icon, png or name\n", 
                         dir_entry->d_name);
              mb_dotdesktop_free(dd);
            }
            else
            fprintf(stderr, "mb-applet-menu-launcher: failed to parse %s :( \n", dir_entry->d_name);
          }
      }
  
      closedir(dp);
    }
  /* Now parse old Debian / Familiar Menu entrys */
  chdir(orig_wd);

  if (WantDebianMenus)
    {
      strcpy(dirs[1], (char *)getenv("HOME"));
      strcat(dirs[1], "/.menu");
      
      for(i=0; i<2; i++)
      {
        if ((dp = opendir(dirs[i])) == NULL)
          {
            fprintf(stderr, "mb-applet-menu-launcher: failed to open %s\n", dirs[i]);
            continue;
          }
        
        chdir(dirs[i]);
        while((dir_entry = readdir(dp)) != NULL)
          {
            lstat(dir_entry->d_name, &stat_info);
            if (!(S_ISDIR(stat_info.st_mode)))
            {
              DBG("file %s \n", dir_entry->d_name);
              
              fp = fopen(dir_entry->d_name, "r");
              buf = malloc(sizeof(char) * (stat_info.st_size + 1));
              len = fread(buf, 1, stat_info.st_size, fp);
              if (len >= 0) buf[len] = '\0';
              if (!(parse_menu_file(buf)))
                fprintf(stderr, "mb-applet-menu-launcher: had problems parsing %s. Ignoring. \n",
                      dir_entry->d_name);
              DBG("done\n\n");
              fclose(fp);
              free(buf);
            }
          }

        closedir(dp);

      }
      chdir(orig_wd);
    }

}

static void
menu_get_popup_pos (MBTrayApp *app, int *x, int *y)
{
  int abs_x, abs_y, menu_h, menu_w;
  mb_tray_app_get_absolute_coords (app, &abs_x, &abs_y);
  mb_menu_get_root_menu_size(app_data->mbmenu, &menu_w, &menu_h);

  if (mb_tray_app_tray_is_vertical (app))
    {
      /* XXX need to figure out menu size before its mapped 
           so we can figure out offset for east panel
      */
      *y = abs_y + mb_tray_app_height(app);

      if (abs_x > (DisplayWidth(mb_tray_app_xdisplay(app), mb_tray_app_xscreen(app)) /2))
      *x = abs_x - menu_w - 2;
      else
      *x = abs_x + mb_tray_app_width(app) + 2;
    }
  else
    {
      *x = abs_x;
      if (abs_y > (DisplayHeight(mb_tray_app_xdisplay(app), mb_tray_app_xscreen(app)) /2))
      *y = abs_y - 2;
      else
      *y = abs_y + mb_tray_app_height(app) + menu_h;
    }
}

void
button_callback (MBTrayApp *app, int x, int y, Bool is_released )
{
  int abs_x, abs_y;
  static Bool next_cancels;

#ifdef USE_DNOTIFY
  sigset_t block_sigset;
#endif

  app_data->button_is_down = True;
  if (is_released) app_data->button_is_down = False;

  if (is_released && !next_cancels)
    {

#ifdef USE_DNOTIFY            /* block any reloads while active */
      sigemptyset(&block_sigset);
      sigaddset(&block_sigset, SIGRTMIN);
      sigprocmask(SIG_BLOCK, &block_sigset, NULL); 
#endif
        
      menu_get_popup_pos (app, &abs_x, &abs_y);
      mb_menu_activate (app_data->mbmenu, abs_x, abs_y);
    }
  else
    if (mb_menu_is_active(app_data->mbmenu))
      next_cancels = True;
    else
      next_cancels = False;

  mb_tray_app_repaint (app);
}

void
paint_callback (MBTrayApp *app, Drawable drw )
{
  MBPixbufImage *img_bg = NULL;
  MBPixbufImage *img_button = NULL;
  
  img_button = ( app_data->button_is_down ? app_data->img_tray_active_scaled : app_data->img_tray_scaled ); 

  img_bg = mb_tray_app_get_background (app, app_data->pb);

  mb_pixbuf_img_copy_composite (app_data->pb, img_bg, 
                        img_button, 
                        0, 0, 
                        mb_pixbuf_img_get_width(app_data->img_tray_scaled), 
                        mb_pixbuf_img_get_height(app_data->img_tray_scaled), 
                        0, 0 );
  
  mb_pixbuf_img_render_to_drawable (app_data->pb, img_bg, drw, 0, 0);

  mb_pixbuf_img_free( app_data->pb, img_bg );
}

void
resize_callback (MBTrayApp *app, int w, int h)
{
  if (app_data->img_tray_scaled) 
    mb_pixbuf_img_free(app_data->pb, 
                   app_data->img_tray_scaled);

  app_data->img_tray_scaled = mb_pixbuf_img_scale(app_data->pb, 
                                      app_data->img_tray, 
                                      w, h);
  if (app_data->img_tray_active_scaled) 
    mb_pixbuf_img_free(app_data->pb, 
                   app_data->img_tray_active_scaled);

  app_data->img_tray_active_scaled 
    = mb_pixbuf_img_scale(app_data->pb, 
                    app_data->img_tray_active, 
                    w, h);
}

void 
theme_callback (MBTrayApp *app, char *theme_name)
{
  if (!theme_name) return;
  if (app_data->theme_name) free(app_data->theme_name);
  app_data->theme_name = strdup(theme_name);

  if (app_data->mbmenu != NULL)
    {
      mb_menu_free(app_data->mbmenu);
      build_menu();
      load_icon();
      resize_callback (app, mb_tray_app_width(app), mb_tray_app_width(app) );
      mb_tray_app_repaint (app_data->tray_app);
    }
}

void
xevent_callback (MBTrayApp *app, XEvent *ev)
{
#ifdef USE_DNOTIFY
  sigset_t block_sigset;
#endif

  mb_menu_handle_xevent (app_data->mbmenu, ev);  

#ifdef USE_DNOTIFY
  if (!mb_menu_is_active(app_data->mbmenu))
    {                         /* Unblock any dnotify signals */
      sigemptyset(&block_sigset);
      sigaddset(&block_sigset, SIGRTMIN);
      sigprocmask(SIG_UNBLOCK, &block_sigset, NULL); 
    }
#endif

#define MB_CMD_SHOW_EXT_MENU 6

  if (ev->type == ClientMessage)
    {
      if (ev->xclient.message_type == app_data->mbcommand_atom
        && ev->xclient.data.l[0] == MB_CMD_SHOW_EXT_MENU )
      {
#ifdef USE_DNOTIFY
        sigemptyset(&block_sigset);
        sigaddset(&block_sigset, SIGRTMIN);
#endif
        if (!mb_menu_is_active(app_data->mbmenu)) 
          {
            int abs_x, abs_y;
#ifdef USE_DNOTIFY
            sigprocmask(SIG_BLOCK, &block_sigset, NULL); 
#endif
            menu_get_popup_pos (app, &abs_x, &abs_y);
            mb_menu_activate(app_data->mbmenu, abs_x, abs_y);
          } else {
            mb_menu_deactivate(app_data->mbmenu);
#ifdef USE_DNOTIFY
            sigprocmask(SIG_UNBLOCK, &block_sigset, NULL); 
#endif
          }
      }
    }

  if (WantReload && !mb_menu_is_active(app_data->mbmenu))
    {
      DBG("reloading menu\n");
      mb_menu_free(app_data->mbmenu);
      build_menu();
      WantReload = False;
    }
}

void 
load_icon(void)
{
 char *icon_path = NULL;
 
 if (app_data->img_tray) 
    mb_pixbuf_img_free(app_data->pb, app_data->img_tray);

 if (app_data->img_tray_active) 
    mb_pixbuf_img_free(app_data->pb, app_data->img_tray_active);
 
 icon_path = mb_dot_desktop_icon_get_full_path (app_data->theme_name, 
                                    16, 
                                    TRAY_IMG );

  if (icon_path == NULL 
      || !(app_data->img_tray 
         = mb_pixbuf_img_new_from_file(app_data->pb, icon_path)))
    {
      fprintf(stderr, "mb-applet-menu-launcher: failed to load panel icon\n");
      exit(1);
    }

  free(icon_path);

  icon_path = mb_dot_desktop_icon_get_full_path (app_data->theme_name, 
                                     16, 
                                     TRAY_IMG_ACTIVE );

  if (icon_path == NULL 
      || !(app_data->img_tray_active
         = mb_pixbuf_img_new_from_file(app_data->pb, icon_path)))
    {
      int x, y;

      app_data->img_tray_active 
      = mb_pixbuf_img_clone(app_data->pb, app_data->img_tray);

      for (x=0; x<mb_pixbuf_img_get_width(app_data->img_tray_active); x++)
      for (y=0; y<mb_pixbuf_img_get_height(app_data->img_tray_active); y++)
        {
          int aa;
          unsigned char r,g,b,a;
          mb_pixbuf_img_get_pixel(app_data->pb, app_data->img_tray_active,
                            x, y, &r, &g, &b, &a);

          aa = (int)a;
          aa -=  0x80; if (aa < 0) aa = 0;

          mb_pixbuf_img_set_pixel_alpha(app_data->img_tray_active, 
                                x, y, aa);
        }
    }

  if (icon_path) free(icon_path);
}

int
main( int argc, char *argv[])
{
  MBTrayApp *app = NULL;
  struct sigaction act;

#ifdef USE_DNOTIFY
  int fd;
#endif

  app_data = NEW(AppData);
  memset(app_data, 0, sizeof(AppData));

  app = mb_tray_app_new ( "App Launcher",
                    resize_callback,
                    paint_callback,
                    &argc,
                    &argv );  

  if (app == NULL) usage();
  
  if (argc > 1 && strstr(argv[1], "-h"))
    usage();

  if (getenv("MB_USE_DEB_MENUS"))
    WantDebianMenus = True;

  app_data->tray_app = app;

  app_data->mbtheme_atom 
    = XInternAtom(mb_tray_app_xdisplay(app), "_MB_THEME", False);
  app_data->mbcommand_atom 
    = XInternAtom(mb_tray_app_xdisplay(app), "_MB_COMMAND", False);
  
  app_data->mbmenu = mb_menu_new(mb_tray_app_xdisplay(app), 
                         mb_tray_app_xscreen(app));
  
#ifdef USE_LIBSN
  
  app_data->sn_display = sn_display_new (mb_tray_app_xdisplay(app), 
                                NULL, NULL); 

#endif

   app_data->pb = mb_pixbuf_new(mb_tray_app_xdisplay(app), 
                        mb_tray_app_xscreen(app));

   XSelectInput (mb_tray_app_xdisplay(app), mb_tray_app_xrootwin(app), 
             PropertyChangeMask|SubstructureNotifyMask);

   mb_tray_app_set_button_callback (app, button_callback );

   mb_tray_app_set_xevent_callback (app, xevent_callback );

   mb_tray_app_set_theme_change_callback (app, theme_callback );

   /* Make the tray app end up on right of mb panel */
   mb_tray_app_request_offset (app, -1); 

   load_icon();

   build_menu();

   /* Set up signals */

   act.sa_flags = 0;
   sigemptyset(&act.sa_mask);
   act.sa_handler = reap_children;
   sigaction(SIGCHLD, &act, NULL);

#ifdef USE_DNOTIFY

#define DD_DIR DATADIR "/applications"

   act.sa_sigaction = reload_menu;
   sigemptyset(&act.sa_mask);
   act.sa_flags = SA_SIGINFO;
   sigaction(SIGRTMIN, &act, NULL);
   
   fd = open(DD_DIR, O_RDONLY);
   fcntl(fd, F_SETSIG, SIGRTMIN);
   fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT);
   
#endif 

  mb_tray_app_set_icon(app, app_data->pb, app_data->img_tray);

  mb_tray_app_main (app);
   
   return 1;
}



Generated by  Doxygen 1.6.0   Back to index