aboutsummaryrefslogblamecommitdiffstats
path: root/src/bin/e_menu.c
blob: ec3f4685318db4e9a904e45dfbde46256a422d55 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


              
  






                                                               







                                                                  
                                                                  

   

                                                


                       
                   
                        

  
                               
























                                                                        
     
                                                
      
                                             
                                                  









                                                                                                                  

                                                                                                    
                                                                                     




                                                                              
                                                                                                 

                                                                                                     
 
                             
                                           

                                               
                                                    
                                                                 
                                            
                                              






                                                      
                                     

                                    
                                  
                                           
 


                                          




                              
 

                                           

                                       







                                     
                       
 




                                                           



                                       


            

                                         



                                     
             



                                       


             
                                     
           

                 




                                                                                               
 
                      


            
           

                     
                                                  
 
                
                       
                          
                                                   
 
                             
                          
 


            
          

                     


                                     
      

                                                                    
                      

                                                               





                                    
              


                
 
                                                         


                       
                      


            
          
                                                                                 

                     
                                       
                        
                                          
                                          
                             
                                 
                                      

                

                             
      


                                     







                                                              
                                      
                           




                                 
                                   







                                                              
                                     









                                                              
                                     










                                                 
              



                                 
      

 
          
                                                                                                               

                    
 
                     
                                       
                        
                                          
                                          
                             
                                 
                                      

                

                             
      


                                     






                                                              
                                      




                           
                                   






                                                              
                                     








                                                              
                                     


                                          
              


                         
      

                                           
                    

                                                                            

 
          
                                                                             



                     
                                       
                        
                                          
                                          
                             
                                 
                                      

                

                             
      


                                     







                                                              
                                      
                           




                                 
                                   







                                                              
                                     









                                                              
                                     


                                          
              


                         
      



                                           
          


                            
                                       
                          





                                                               
         


                               
                                                 



                    
         


                               
                                                 




                                    
          
                                              

                     
                                       



                                                                         

                                              
      
                                                            

                               





                                                                            

 
          
                                                                         
 
                               

                                          
      

 
          
                                                    




                                       

                                          
      
                
                                                  
       
                        

                  
 
          


                                                    

                                                      
           
                      
                                                     
      


                                                         


      
                                
                                                                                                                                         

                        
                                       

                                                      
                                                          
      

                                                         
      
           




                                                         

                                    



                                                                   


             
          




                                                          






                                                                

 
          
                                                                                            

                     
                                       



                                  
          
                                                                                               

                     
                                       



                                     
              




                                  
                                                    
           
                                                         
                                  


              
 
                   


                          
 
                                  

                                                                         
                

                                                           


             
                   






                                                     


                                                                
      
 




                                                                         
                     
 

                                                                   
                                    


       

                                                   
      
 


             
                   


                                  
                                                    
                                                    

 
         
                                          
 

                          
             
 
                                 
                                       
                                                   
                                             
      

                                



             
          
                                                            

                      
                                             
                                                             
                                
            

                                                        

                       


                                              
                                                     

                                                      



                         
          
                                                                             

                      
                                             
                                                             
                                  

                                                                 

                                                



                         
          
                                                         

                      
                                             
                                                                 
                                  
            
                                                  
                    
                                                      



                         
          

                                                     

                                  
                         
              
                      
                                             

                                    
                           
                                                          
                                        


                         

                                  

                                        

                                                  

                               
                                            



                                                                              


                                                                          


                                                                            
                           


                                                 
                                            

                                                                     




                                                                  
                                                  


                                                                


                                                                  


                                                                    


                                                             







                                                                    
                                                  
      

                                          


                                                                      
                                                                         
                   
      
 

                                                             

                                

 
          


                                                   
                                             
                                                                          




                         
          


                                               
                                             
                                                                  




                         
          


                                               
                                             
                                                                  




                         
          


                                                      
                                             
                                       




                          
          


                                                
                                             


                             




                                                                         
                                     
                                                                       
                                       
                                                                         
                                      


                                                                          


       




                                                                          
                                     
                                                                        
                                       
                                                                          
                                      


                                                                           


           



                                
 






                                                            


      
         


                                       
                                                       


                     
          
                                                                                                                 

                      
                                             
                      
                              

 
          
                                                                                                                   






                                             
          
                                                                                                                             



                                             
                                          
                                 
                                                                     

 
          
                                                                                                                              



                                             
                                           

 
          
                                                                                                                






                                             
          

                                                   

                         
                      
                                             
                             

                                    
                                 
      




                                        
                



                                              

                                                                         
                                                                                              

                                                                    





                                                                               
                                     
                                                                             
                                       
                                                                               
                                      


                                                                              

                                 
                                              



                                                                                      


                                                                              
      
                                      
      
                                         
                       
                                      




                                                                                 
                                     
                                                                               
                                       
                                                                                 
                                      


                                                                                

                                 
                                              



                                                                                        

                                                                                
      
                                

 
                   




                              
          





                                 
          






                                                      



                                                                              
                                     
                                                                            
                                      
                                                                             


       


                                                                             
                                     
                                                                           
                                      
                                                                            


      
          




                                                                            

                                        
 





                                                           
                                                    
                                    
                                                           
                                           
      


                                                   







                                                                                                                        
           

                                                                        
                                           
      
                                                
                                             


                                          
           





                                  
                                                      




                                          
                



                                                                      
                     






                                                           
                     
                

                                  
                              
                                                                  
                              
           

                                                          
                                           
      
                                
                                   
                           

                                              

                                                            
           

                                
                                                   
      
                                                                       
           
                                  

                                                      
      
                              
      





                                                                    

                                                 
                                
 

                        
                                          
           
                                       
                                    
                                        
           


      

                      
 
                                        

 





                                                                            


                               
 

                    
                                                                            
                          

 


                       

                         
                               
 
                               
                                                                          

           
                                     
 



                                                
      
                                                
                      
                                    

                           
                                                  
                                

                         

                                                               
      

                                                                      
                                                       





                                  
                                                             
                                                                       

                   













                                                                                                   
                




                                                                                           

                                                      
                                                           


                                                        






                                                                                      
 


             

                                                   



                                           





                                                                                        
 


             








                                                                                           
 










                                                                                             
 







                                             
                                                                                                            
 
                        


           


                                     
                             
 
                                      

                     





                                                                    
                                     

                             
                                                                           


       

                                            



                                                                                            

                                                                                           













                                                                               
                                     
                                                        
                                      
                                 
                                     

                            



                                                 
                                                          


                                                                     
                                 
                                                       


                                                                    


                                                                      



                                                 
                                                          


                                                                     
                                 
                                                       


                                                                    


                                                                      



                                                           
                                                          

                                                  
                                                       
           
                                                                                  






                                                                        
                                                                







                                         
                                                        
 
                                                                                                                              
                                                                                                                                        


















                                                                                          
                                                                       












                                                                    
                                                                  
                                           
                                                                                          
                                                              











                                                                          



                                    
                                                                       
                                                              
                                                               
                                                            


                                                                          



                                                                             



                                                      
                                                                


                                                                     



                                                                         




                                                           
                                                        

                                                  
                                                       




                                                 
                                                         




                                                                     
                                 
                                                       


                                                                   


                                                                     



                                                           
                                                         

                                                  
                                                       



                                                       
                                                           


                                                                       
                                 
                                                       


                                                                     


                                                                       



                                                           
                                                           

                                                  
                                                       


                                                                    

                                                       
                                                                    


                                                 
                                                    





                          
                
                   
 
                                          
 

                                              
                                          
                                               
                              
 

                                
                                              
                                                                                       

                       


                                                                      
      
 
                                                                       
                                                     







                                                                                                      
                                
                                                     
                           
                                                                                      
                                                                                          
                                 
                                                                                    
 

                                     
 
                                  
 
                            
                   




                                      
                
                   
                                     







                                            
                            
                                
                                              
 
                                     
      



                                          
                                                     










                                                                         


                 
















                                                                        


                     











                                                          


                       






                                              
      


                                                                     
                      
                                                                             
                                       
      
                                     
      
                                   



                                        
                    

                          



                                                                                                   

                                   
           


                                                                                                               
                     
           


                                                                                                          
           
            













                                                                                                                    
                                                           



                                                                    


                                                             
                 
      

                                                                
                                                              
                                                                                    
                                                     






















                                                                   




                            
                

                   
                            

                                                           










                                                                                                                   








                                                                                                    
                                     
                                


                                                     


                       
                  
                              
                  


           
                                                  
 
                               
                
 



                                                         
                                     
      
                                     
                                     
           
                                    

                    
                                   
      
                  

                  


                                                                              
                                                                 
                                                               

                                    

                              
      
                               
                   
      




                                                              
                                                                  
           
      
                      




                            

                  
 


                                    
      


                                    
      


                                   




                                    
                  
                 
             
 


                                    
      






                                    






                                         
                                                  

                            

                                          


                                      

                                                                    

                   
                  
 





                                                     
                                   
      




                                           
                                 
                              

                                                                      




                             

                      
                          
 

                                                                        
 
                                          
                             
      
                                                                                       
                                        
                                                                 
                                             
                                                             

                                               
                                                     
              

       
      
                                         

                                                                            
                                                                                 
                                                                       
            
                                        
      
 
                                            


                                     
                                                                        

                                




                         
                   
 

                                  
      






                                                         



             




                                     




                                                                    



            


                                
                   
                 
 

                                       
                
      










                                                                  
 


                                         
      
 





                                    
                   
                 
 

                                       
                
      










                                                                  
 


                                         
      
 



                            


                                 
                 

                   


                            










                                                     







                                
                 

                   


                            










                                                     








                                
                 
              
 


                                  


                                       

                
                                      
      

                                
      
                   




                                    
                                                   


                   
                           





                                                
          
      


                                                





                                                                         








                                                                                                     



                
                               
                           

                          

                               


                                                                   
                                                                                  
                           
      








                                         







                                    






                                  



                                    







                                                              


                











                                  






                                              
      
                           






                            
                 
 
                                
                                           

                         

                                                
      

                                    

                             
                                 



                                    



                           
                 
 
                                
                                           
                         
                                 

                                                
      

                                    

                             
                                 


                                    
     
           



                           
                 
              
 


                                  


                                       

                
                                      
      






                                              

      
 
      



                        

                                                             




                             
                              

 
                  


                                  
                                               



                 


                                              
                
             



                
             
 

                                           



















                                                                                                    


                  
                              


                      
                              


                       
                              


                      
                              






                                 
                


                                           
      

                       







                                    

                    
 











                                                         
      
                                                                 
      
                                                         
      
                                                                 


                                          
              
           
                                                                                  


                                                                         
                                                                                  



                                                                         



                                                  

                                                                           
                                                      
                                                




                                             

                                  
 

                               
                                                                  

                                                            

                                  

                                                            

                                  



                               





















                                                                           



                                                         
 







                      
     

                            

                                    
                                

              

                                    
                                

              
 

                                          



                                     
                                                    


                      
           
                    








                                                                


                             












                                                                
           
                    
                                     
                                                    

                      



            
           
                                                                                                                  
 
                          
 
                            

                                                                                          



                                 
                                                                                                                   
 
                          

                                                                                          


                                 
                
                                                                
 
                                                               
                                      
                                                                        
                                  
                                                                        
                                 
                                                                          
                             
                                                                        
                                   
                                                                      
                                  
                                      

                                                                           
      

                                 
      
                                       
                              
                                                                  
                                   
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  
                                                                  
                                  

                                             
                                 

 
                                                                        
                                                                        


                                                       
           
                                                                    
 




                              

 
                
                                                                                
 
                                
 
              

                                 

                                   

                                      
 



                                  
                                                      
                                                         



                                                             
                                     
 
                                 

 
                
                                                                              
 
                                
                  
               
 
                                                 
              
                                                              
 
                                             

                                                         
      

                                      
      
 
                                 
      
                                                               
                                                                                  
           
      
       



                                       
                    

                                                              

                                                  

                                      

                                   

                
                                                       
                                          
                                 


                              
                                       
                              
                                 

 
                
                                                                                
 
                              

                      



                              
 
              
                                                                
                                                                    


                             
                                                        


                                                                               
 


                                           
      



                                                          
           

                                        
                
                                  
 


                                                 
                
           



                                                                                
                                   
      
                                
           
                                                                                                                                         
                







                                                                                                                                            

                                                              
                
           
      


                                

                     
                                
                                    
                                 

 
                
                                                                                 
 
                               
 
              
                                                                

                          
              
 

                                           


                                 
              
 

                                       
      
                                 

 
                
                                                  




                 
 
                             
                                      





                                 









                                                                  


                            









                                                                  




                                                                  

                                       


            
 
           
                                                                                                    





                            
                                     

                                
 

                                              
 
                                     

             
 
#include "e.h"

/* TODO List:
 *
 * * support change of menu items after realize
 * * support add/del of menu items after realize
 * * support text/color classes
 * * refcount menu up while looping thru and calling other fn's
 * * support alignment (x, y) as well as spawn direction
 * * need different menu style support for different menus
 * * add menu icon/title support
 * * use event timestamps not clock for "click and release" detect
 * * menu icons can set if/how they will be scaled
 * * support move/resize of "box" that spawned the menu
 * * add image item (label is replaced by image/icon)
 * * add generic evas object item type (label replaced by object)
 * * allow menus to stretch width/height to fit spawner widget/box
 * * allow menus to auto-shrink (horizontally) if forced to
 * * support auto left/right direction spawn
 * * support obscures to indicate offscreen/not visible menu parts
 */

/* local subsystem data types */
typedef struct _E_Menu_Category E_Menu_Category;

struct _E_Menu_Category
{
   void      *data;
   Eina_List *callbacks;
};

/* local subsystem functions */
static void         _e_menu_free(E_Menu *m);
static void         _e_menu_item_free(E_Menu_Item *mi);
static void         _e_menu_item_realize(E_Menu_Item *mi);
static void         _e_menu_realize(E_Menu *m);
static void         _e_menu_items_layout_update(E_Menu *m);
static void         _e_menu_item_unrealize(E_Menu_Item *mi);
static void         _e_menu_unrealize(E_Menu *m);
static void         _e_menu_activate_internal(E_Menu *m, E_Zone *zone);
static void         _e_menu_deactivate_all(void);
static void         _e_menu_deactivate_above(E_Menu *m);
static void         _e_menu_submenu_activate(E_Menu_Item *mi);
static void         _e_menu_submenu_deactivate(E_Menu_Item *mi);
static void         _e_menu_reposition(E_Menu *m);
static int          _e_menu_active_call(void);
static int          _e_menu_realize_call(E_Menu_Item *mi);
static void         _e_menu_item_activate_next(void);
static void         _e_menu_item_activate_previous(void);
static void         _e_menu_item_activate_first(void);
static void         _e_menu_item_activate_last(void);
static void         _e_menu_item_activate_nth(int n);
static void         _e_menu_item_activate_char(const char *key_compose);
static void         _e_menu_activate_next(void);
static void         _e_menu_activate_previous(void);
static void         _e_menu_activate_first(void);
static void         _e_menu_activate_last(void);
#if 0
static void         _e_menu_activate_nth(int n);
#endif
static E_Menu      *_e_menu_active_get(void);
static E_Menu_Item *_e_menu_item_active_get(void);
static Eina_List   *_e_menu_list_item_active_get(void);
static int          _e_menu_outside_bounds_get(int xdir, int ydir);
static void         _e_menu_scroll_by(int dx, int dy);
static void         _e_menu_mouse_autoscroll_check(void);
static void         _e_menu_item_ensure_onscreen(E_Menu_Item *mi);
static int          _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h);
static void         _e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
static void         _e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
static void         _e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
static void         _e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
static void         _e_menu_cb_item_in(void *data, Evas *evas, Evas_Object *obj, void *event_info);
static void         _e_menu_cb_item_out(void *data, Evas *evas, Evas_Object *obj, void *event_info);
static Eina_Bool    _e_menu_cb_key_down(void *data EINA_UNUSED, Ecore_Event_Key *ev);
static Eina_Bool    _e_menu_cb_mouse_down(void *data, int type, void *event);
static Eina_Bool    _e_menu_cb_mouse_up(void *data, int type, void *event);
static Eina_Bool    _e_menu_cb_mouse_move(void *data, int type, void *event);
static Eina_Bool    _e_menu_cb_mouse_wheel(void *data, int type, void *event);
static Eina_Bool    _e_menu_cb_scroll_animator(void *data);
static void         _e_menu_cb_item_submenu_post_default(void *data, E_Menu *m, E_Menu_Item *mi);
static void         _e_menu_category_free_cb(E_Menu_Category *cat);
static void         _e_menu_cb_mouse_evas_down(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED);

/* local subsystem globals */
static Ecore_Window _e_menu_win = UINT_MAX;
static Eina_List *_e_active_menus = NULL;
static E_Menu_Item *_e_active_menu_item = NULL;
static E_Menu_Item *_e_prev_active_menu_item = NULL;
/*static Eina_Hash	   *_e_menu_category_items	= NULL;*/
static Eina_Hash *_e_menu_categories = NULL;
static unsigned int _e_menu_activate_time = 0;
static int _e_menu_activate_floating = 0;
static int _e_menu_activate_maybe_drag = 0;
static int _e_menu_activate_dragging = 0;
static Ecore_Animator *_e_menu_scroll_animator = NULL;
static double _e_menu_scroll_start = 0.0;
static int _e_menu_x = 0;
static int _e_menu_y = 0;
static unsigned int _e_menu_time = 0;
static int _e_menu_autoscroll_x = 0;
static int _e_menu_autoscroll_y = 0;
static Eina_List *handlers = NULL;
static Eina_Bool _e_menu_lock = EINA_FALSE;

static Eina_Bool pending_feed;
static unsigned int pending_activate_time;

static Eina_List *
_e_active_menus_copy_ref(void)
{
   E_Object *o;
   Eina_List *l, *ret = NULL;

   EINA_LIST_FOREACH(_e_active_menus, l, o)
     {
        ret = eina_list_append(ret, o);
        e_object_ref(o);
     }
   return ret;
}

static Eina_List *
_e_menu_list_free_unref(Eina_List *l)
{
   E_Object *o;
   Eina_List *ll, *lll;

   /* list must be freed in reverse to ensure that submenus
    * (which are added to the end of the list)
    * are deleted before their parents
    */
   EINA_LIST_REVERSE_FOREACH_SAFE(l, ll, lll, o)
   {
      e_object_unref(o);
      l = eina_list_remove_list(l, ll);
   }
   return l;
}

/* macros for debugging menu refcounts */
#if 0
#define e_object_ref(X)   do {      \
       int xx;                      \
       xx = e_object_ref(X);        \
       INF("REF: %p || %d", X, xx); \
  } while (0)
#define e_object_unref(X) do {        \
       int xx;                        \
       xx = e_object_unref(X);        \
       INF("UNREF: %p || %d", X, xx); \
  } while (0)
#endif

/* externally accessible functions */
EINTERN int
e_menu_init(void)
{
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_menu_cb_mouse_down, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _e_menu_cb_mouse_up, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE, _e_menu_cb_mouse_move, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL, _e_menu_cb_mouse_wheel, NULL);
   _e_menu_categories = eina_hash_string_superfast_new((Eina_Free_Cb)_e_menu_category_free_cb);

   e_int_menus_init();
   return 1;
}

EINTERN int
e_menu_shutdown(void)
{
   E_FREE_LIST(handlers, ecore_event_handler_del);

   if (!x_fatal)
     e_menu_hide_all();
   _e_active_menus = NULL;
   E_FREE_FUNC(_e_menu_categories, eina_hash_free);

   _e_menu_lock = EINA_FALSE;
   e_int_menus_shutdown();

   return 1;
}

E_API void
e_menu_hide_all(void)
{
   E_Menu *m;

   EINA_LIST_FREE(_e_active_menus, m)
     {
        if (m->post_deactivate_cb.func)
          m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
        m->active = 0;
        if (m->comp_object == e_comp->autoclose.obj)
          e_comp_object_util_autoclose(NULL, NULL, NULL, NULL);
        _e_menu_unrealize(m);
        m->in_active_list = 0;
        e_object_unref(E_OBJECT(m));
     }
}

E_API E_Menu *
e_menu_new(void)
{
   E_Menu *m;

   m = E_OBJECT_ALLOC(E_Menu, E_MENU_TYPE, _e_menu_free);
   if (!m) return NULL;
   m->cur.w = 1;
   m->cur.h = 1;
   m->category = NULL;
   return m;
}

E_API void
e_menu_activate_key(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   E_OBJECT_CHECK(zone);
   E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
   if (_e_active_menus) e_menu_hide_all();
   _e_menu_activate_time = 0;
   _e_menu_activate_floating = 0;
   _e_menu_activate_internal(m, zone);
   if (!m->zone)
     {
        e_menu_deactivate(m);
        return;
     }
   switch (dir)
     {
      case E_MENU_POP_DIRECTION_LEFT:
        _e_menu_realize(m);
        m->cur.x = x - m->cur.w;
        m->cur.y = y;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_RIGHT:
        _e_menu_realize(m);
        m->cur.x = x + w;
        m->cur.y = y;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_UP:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y - m->cur.h;
        _e_menu_activate_last();
        break;

      case E_MENU_POP_DIRECTION_DOWN:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y + h;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_AUTO:
      {
         int pos = 0;

         pos = _e_menu_auto_place(m, x, y, w, h);
         if (pos == 4)
           _e_menu_activate_last();
         else
           _e_menu_activate_first();
      }
      break;

      default:
        m->cur.x = x + w;
        m->cur.y = y + h;
        _e_menu_activate_first();
        break;
     }
}

E_API void
e_menu_activate_mouse(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir, unsigned int activate_time)
{
   E_Menu_Item *pmi;

   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   E_OBJECT_CHECK(zone);
   E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
   if (_e_active_menus) e_menu_hide_all();
   _e_menu_activate_time = 0;
   _e_menu_activate_floating = 0;
   _e_menu_activate_internal(m, zone);
   if (!m->zone)
     {
        e_menu_deactivate(m);
        return;
     }
   switch (dir)
     {
      case E_MENU_POP_DIRECTION_LEFT:
        _e_menu_realize(m);
        m->cur.x = x - m->cur.w;
        m->cur.y = y;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        break;

      case E_MENU_POP_DIRECTION_RIGHT:
        _e_menu_realize(m);
        m->cur.x = x + w;
        m->cur.y = y;
        break;

      case E_MENU_POP_DIRECTION_UP:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y - m->cur.h;
        break;

      case E_MENU_POP_DIRECTION_DOWN:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y + h;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        break;

      case E_MENU_POP_DIRECTION_AUTO:
        _e_menu_auto_place(m, x, y, w, h);
        break;

      default:
        m->cur.x = x + w;
        m->cur.y = y + h;
        break;
     }
   pmi = _e_menu_item_active_get();
   if (pmi) e_menu_item_active_set(pmi, 0);
   pending_feed = 1;
   if (!activate_time) activate_time = lround(ecore_loop_time_get() * 1000);
   _e_menu_activate_time = pending_activate_time = activate_time;
}

E_API void
e_menu_activate(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
{
   E_Menu_Item *pmi;

   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   E_OBJECT_CHECK(zone);
   E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
   if (_e_active_menus) e_menu_hide_all();
   _e_menu_activate_time = 0;
   _e_menu_activate_floating = 0;
   _e_menu_activate_internal(m, zone);
   if (!m->zone)
     {
        e_menu_deactivate(m);
        return;
     }
   switch (dir)
     {
      case E_MENU_POP_DIRECTION_LEFT:
        _e_menu_realize(m);
        m->cur.x = x - m->cur.w;
        m->cur.y = y;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_RIGHT:
        _e_menu_realize(m);
        m->cur.x = x + w;
        m->cur.y = y;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_UP:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y - m->cur.h;
        _e_menu_activate_last();
        break;

      case E_MENU_POP_DIRECTION_DOWN:
        _e_menu_realize(m);
        m->cur.x = x;
        if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
          m->cur.x = x + w - m->cur.w;
        m->cur.y = y + h;
        if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
          m->cur.y = y + h - m->cur.h;
        _e_menu_activate_first();
        break;

      case E_MENU_POP_DIRECTION_AUTO:
        _e_menu_auto_place(m, x, y, w, h);
        break;

      default:
        m->cur.x = x + w;
        m->cur.y = y + h;
        break;
     }
   pmi = _e_menu_item_active_get();
   if (pmi) e_menu_item_active_set(pmi, 0);
}

E_API void
e_menu_deactivate(E_Menu *m)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   if (!m->active) return;
   m->cur.visible = 0;
   m->active = 0;
   if (m->post_deactivate_cb.func)
     m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
}

E_API int
e_menu_freeze(E_Menu *m)
{
   E_OBJECT_CHECK_RETURN(m, 0);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
   m->frozen++;
   return m->frozen;
}

E_API int
e_menu_thaw(E_Menu *m)
{
   E_OBJECT_CHECK_RETURN(m, 0);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
   m->frozen--;
   if (m->frozen < 0) m->frozen = 0;
   return m->frozen;
}

E_API void
e_menu_title_set(E_Menu *m, const char *title)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   if ((m->header.title) && (title) && (!strcmp(m->header.title, title)))
     return;
   if (m->header.title)
     {
        eina_stringshare_del(m->header.title);
        m->header.title = NULL;
     }
   if (title) m->header.title = eina_stringshare_add(title);
   else m->header.title = NULL;
   m->changed = 1;
   edje_object_part_text_set(m->bg_object, "e.text.title", m->header.title);
   if (m->header.title)
     edje_object_signal_emit(m->bg_object, "e,action,show,title", "e");
   else
     edje_object_signal_emit(m->bg_object, "e,action,hide,title", "e");
   edje_object_message_signal_process(m->bg_object);
}

E_API void
e_menu_icon_file_set(E_Menu *m EINA_UNUSED, const char *icon EINA_UNUSED)
{
   /* FIXME: support menu icons
      E_OBJECT_CHECK(m);
      E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
    */
}

E_API void
e_menu_category_set(E_Menu *m, const char *category)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   if (m->category)
     {
        eina_stringshare_del(m->category);
        m->category = NULL;
     }
   if (category)
     m->category = eina_stringshare_add(category);
   else
     m->category = NULL;
   m->changed = 1;
}

E_API void
e_menu_category_data_set(char *category, void *data)
{
   E_Menu_Category *cat;

   cat = eina_hash_find(_e_menu_categories, category);
   if (cat)
     cat->data = data;
   else   /* if it isn't found create the new hash */
     {
        cat = calloc(1, sizeof(E_Menu_Category));
        cat->data = data;
        eina_hash_add(_e_menu_categories, category, cat);
     }
}

E_API E_Menu_Category_Callback *
e_menu_category_callback_add(char *category, void (*create_cb)(void *data, E_Menu *m, void *category_data), Ecore_Cb free_cb, void *data)
{
   E_Menu_Category *cat;
   E_Menu_Category_Callback *cb = NULL;

   cat = eina_hash_find(_e_menu_categories, category);
   if (!cat)   /* if it isn't found create the new hash */
     {
        cat = calloc(1, sizeof(E_Menu_Category));
        eina_hash_add(_e_menu_categories, category, cat);
     }
   if (cat)
     {
        cb = calloc(1, sizeof(E_Menu_Category_Callback));
        if (cb)
          {
             cb->data = data;
             cb->create = create_cb;
             cb->free = free_cb;
             cb->category = eina_stringshare_add(category);
             cat->callbacks = eina_list_append(cat->callbacks, cb);
          }
     }
   return cb;
}

E_API void
e_menu_category_callback_del(E_Menu_Category_Callback *cb)
{
   E_Menu_Category *cat;

   if (cb)
     {
        cat = eina_hash_find(_e_menu_categories, cb->category);
        if (cat)
          cat->callbacks = eina_list_remove(cat->callbacks, cb);
        eina_stringshare_del(cb->category);
        free(cb);
     }
}

E_API void
e_menu_pre_activate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   m->pre_activate_cb.func = func;
   m->pre_activate_cb.data = data;
}

E_API void
e_menu_post_deactivate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
{
   E_OBJECT_CHECK(m);
   E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
   m->post_deactivate_cb.func = func;
   m->post_deactivate_cb.data = data;
}

E_API E_Menu *
e_menu_root_get(E_Menu *m)
{
   E_Menu *ret;

   E_OBJECT_CHECK_RETURN(m, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
   ret = m;
   while ((ret->parent_item) && (ret->parent_item->menu))
     ret = ret->parent_item->menu;

   return ret;
}

E_API E_Menu_Item *
e_menu_item_new(E_Menu *m)
{
   E_Menu_Item *mi;

   E_OBJECT_CHECK_RETURN(m, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
   mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
   mi->menu = m;
   mi->menu->items = eina_list_append(mi->menu->items, mi);
   mi->list_position = eina_list_last(mi->menu->items);
   return mi;
}

E_API E_Menu_Item *
e_menu_item_new_relative(E_Menu *m, E_Menu_Item *rel)
{
   E_Menu_Item *mi;
   E_OBJECT_CHECK_RETURN(m, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
   if (rel)
     {
        E_OBJECT_CHECK_RETURN(rel, NULL);
        E_OBJECT_TYPE_CHECK_RETURN(rel, E_MENU_ITEM_TYPE, NULL);
        if (rel->menu != m) return NULL;
     }

   mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
   mi->menu = m;

   if (rel)
     {
        Eina_List *l;

        l = eina_list_data_find_list(m->items, rel);
        m->items = eina_list_append_relative_list(m->items, mi, l);
        mi->list_position = l->next;
     }
   else
     {
        m->items = eina_list_prepend(m->items, mi);
        mi->list_position = m->items;
     }

   return mi;
}

E_API E_Menu_Item *
e_menu_item_nth(E_Menu *m, int n)
{
   E_OBJECT_CHECK_RETURN(m, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
   return (E_Menu_Item *)eina_list_nth(m->items, n);
}

E_API int
e_menu_item_num_get(const E_Menu_Item *mi)
{
   const Eina_List *l;
   const E_Menu_Item *mi2;
   int i = 0;

   E_OBJECT_CHECK_RETURN(mi, -1);
   E_OBJECT_CHECK_RETURN(mi->menu, -1);
   E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_TYPE, -1);
   EINA_LIST_FOREACH(mi->menu->items, l, mi2)
     {
        if (mi2 == mi) return i;
        i++;
     }
   return -1;
}

E_API void
e_menu_item_icon_file_set(E_Menu_Item *mi, const char *icon)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
       ((!mi->icon) && (!icon)))
     return;
   if (mi->icon) eina_stringshare_del(mi->icon);
   if (mi->icon_key) eina_stringshare_del(mi->icon_key);
   mi->icon = NULL;
   mi->icon_key = NULL;
   if (icon)
     {
        mi->icon = eina_stringshare_add(icon);
        if (eina_str_has_extension(mi->icon, ".edj"))
          mi->icon_key = eina_stringshare_add("icon");
     }
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_icon_edje_set(E_Menu_Item *mi, const char *icon, const char *key)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
       ((!mi->icon) && (!icon)) ||
       ((key) && (mi->icon_key) && (!strcmp(key, mi->icon_key))))
     return;
   eina_stringshare_replace(&mi->icon, icon);
   eina_stringshare_replace(&mi->icon_key, key);
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_label_set(E_Menu_Item *mi, const char *label)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->label) && (label) && (!strcmp(label, mi->label))) ||
       ((!mi->label) && (!label)))
     return;
   if (mi->label) eina_stringshare_del(mi->label);
   mi->label = NULL;
   if (label) mi->label = eina_stringshare_add(label);
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_submenu_set(E_Menu_Item *mi, E_Menu *sub)
{
   Eina_Bool submenu = EINA_FALSE;
   Evas_Object *o;
   Eina_List *tmp = NULL;
   int ww, hh;
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);

   tmp = _e_active_menus_copy_ref();
   submenu = !!mi->submenu;
   if (mi->submenu) e_object_unref(E_OBJECT(mi->submenu));
   if (sub) e_object_ref(E_OBJECT(sub));
   mi->submenu = sub;
   mi->changed = 1;
   mi->menu->changed = 1;
   if (!!sub == submenu) goto out;
   if (!mi->bg_object) goto out;
   if (sub) e_object_ref(E_OBJECT(sub));
   _e_menu_lock = EINA_TRUE;
   if ((mi->submenu) || (mi->submenu_pre_cb.func))
     {
        if (mi->submenu_object)
          {
             if (isedje(mi->submenu_object))
               {
                  /* already have a correct submenu object, don't re-set it */
                  _e_menu_lock = EINA_FALSE;
                  if (sub) e_object_unref(E_OBJECT(sub));
                  edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
                  mi->submenu_w = ww;
                  mi->submenu_h = hh;
                  E_WEIGHT(mi->submenu_object, 0, 1);
                  E_FILL(mi->submenu_object);
                  evas_object_size_hint_min_set(mi->submenu_object, ww, hh);
                  goto out;
               }
             evas_object_del(mi->submenu_object);
          }
        o = edje_object_add(mi->menu->evas);
        if (sub && (mi->submenu != sub)) e_object_ref(E_OBJECT(sub));
        mi->submenu = sub;
        mi->submenu_object = o;
        e_theme_edje_object_set(o, "base/theme/menus",
                                "e/widgets/menu/default/submenu");
        evas_object_pass_events_set(o, 1);
        evas_object_show(o);
        elm_box_pack_end(mi->container_object, o);
        edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
        mi->submenu_w = ww;
        mi->submenu_h = hh;
        E_WEIGHT(mi->submenu_object, 0, 1);
        E_FILL(mi->submenu_object);
        evas_object_size_hint_min_set(mi->submenu_object, ww, hh);
        edje_object_part_swallow(mi->bg_object, "e.swallow.content",
                                 mi->container_object);
        edje_object_size_min_calc(mi->bg_object, &ww, &hh);
        E_WEIGHT(mi->bg_object, 1, 0);
        E_FILL(mi->bg_object);
        evas_object_size_hint_min_set(mi->bg_object, ww, hh);
     }
   else
     {
        if (mi->submenu_object) evas_object_del(mi->submenu_object);
        o = evas_object_rectangle_add(mi->menu->evas);
        mi->submenu_object = o;
        evas_object_color_set(o, 0, 0, 0, 0);
        evas_object_pass_events_set(o, 1);
        elm_box_pack_end(mi->container_object, o);
     }
   _e_menu_lock = EINA_FALSE;
   if (sub) e_object_unref(E_OBJECT(sub));
   if ((mi->submenu) || (mi->submenu_pre_cb.func))
     {
        if (e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
                                    "e/widgets/menu/default/submenu_bg"))
          goto out;
     }

   e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
                           "e/widgets/menu/default/item_bg");
out:
   _e_menu_list_free_unref(tmp);
}

E_API void
e_menu_item_separator_set(E_Menu_Item *mi, int sep)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->separator) && (sep)) || ((!mi->separator) && (!sep))) return;
   mi->separator = sep;
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_check_set(E_Menu_Item *mi, int chk)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->check) && (chk)) || ((!mi->check) && (!chk))) return;
   mi->check = chk;
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_radio_set(E_Menu_Item *mi, int rad)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (((mi->radio) && (rad)) || ((!mi->radio) && (!rad))) return;
   mi->radio = rad;
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_radio_group_set(E_Menu_Item *mi, int radg)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (mi->radio_group == radg) return;
   mi->radio_group = radg;
   mi->changed = 1;
   mi->menu->changed = 1;
}

E_API void
e_menu_item_toggle_set(E_Menu_Item *mi, int tog)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (mi->separator) return;
   if (tog)
     {
        mi->toggle = 1;
        if (mi->bg_object)
          edje_object_signal_emit(mi->bg_object, "e,state,on", "e");
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,on", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,on", "e");
        if (isedje(mi->submenu_object))
          edje_object_signal_emit(mi->submenu_object, "e,state,on", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,on", "e");
        if (mi->menu->bg_object)
          edje_object_signal_emit(mi->menu->bg_object, "e,state,on", "e");
     }
   else
     {
        mi->toggle = 0;
        if (mi->bg_object)
          edje_object_signal_emit(mi->bg_object, "e,state,off", "e");
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,off", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,off", "e");
        if (isedje(mi->submenu_object))
          edje_object_signal_emit(mi->submenu_object, "e,state,off", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,off", "e");
        if (mi->menu->bg_object)
          edje_object_signal_emit(mi->menu->bg_object, "e,state,off", "e");
     }
   if (tog)
     {
        if (mi->radio)
          {
             const Eina_List *l;
             E_Menu_Item *mi2;

             EINA_LIST_FOREACH(mi->menu->items, l, mi2)
               {
                  if ((mi2 != mi) && (mi2->radio) &&
                      (mi2->radio_group == mi->radio_group))
                    e_menu_item_toggle_set(mi2, 0);
               }
          }
     }
}

E_API int
e_menu_item_toggle_get(E_Menu_Item *mi)
{
   E_OBJECT_CHECK_RETURN(mi, 0);
   E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_ITEM_TYPE, 0);
   return mi->toggle;
}

E_API void
e_menu_item_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   mi->cb.func = func;
   mi->cb.data = (void *)data;
}

E_API void
e_menu_item_realize_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   mi->realize_cb.func = func;
   mi->realize_cb.data = data;
}

E_API void
e_menu_item_submenu_pre_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   mi->submenu_pre_cb.func = func;
   mi->submenu_pre_cb.data = (void *)data;
   if (!mi->submenu_post_cb.func)
     mi->submenu_post_cb.func = _e_menu_cb_item_submenu_post_default;
}

E_API void
e_menu_item_submenu_post_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   mi->submenu_post_cb.func = func;
   mi->submenu_post_cb.data = (void *)data;
}

E_API void
e_menu_item_drag_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   mi->drag_cb.func = func;
   mi->drag_cb.data = data;
}

E_API void
e_menu_item_active_set(E_Menu_Item *mi, int active)
{
   Eina_List *tmp = NULL;

   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (mi->separator) return;
   active = !!active;
   if (active == mi->active) return;
   if ((active) && (!mi->active))
     {
        E_Menu_Item *pmi;

        if (mi->disable) return;
        pmi = _e_menu_item_active_get();
        if (mi == pmi) return;
        if (pmi)
          {
             tmp = _e_active_menus_copy_ref();
             e_menu_item_active_set(pmi, 0);
          }
        if (_e_prev_active_menu_item && (mi != _e_prev_active_menu_item))
          {
             if (mi->menu->parent_item && (_e_prev_active_menu_item != mi->menu->parent_item))
               _e_menu_submenu_deactivate(_e_prev_active_menu_item);
          }
        mi->active = 1;
        _e_active_menu_item = mi;
        if (mi->bg_object)
          edje_object_signal_emit(mi->bg_object, "e,state,selected", "e");
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,selected", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,selected", "e");
        if (isedje(mi->submenu_object))
          edje_object_signal_emit(mi->submenu_object, "e,state,selected", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,selected", "e");
        if (mi->icon_key)
          {
             if (mi->icon_object)
               {
                  if (isedje(mi->icon_object))
                    edje_object_signal_emit(mi->icon_object, "e,state,selected", "e");
                  else
                    e_icon_selected_set(mi->icon_object, EINA_TRUE);
               }
          }
        edje_object_signal_emit(mi->menu->bg_object, "e,state,selected", "e");
        _e_menu_submenu_activate(mi);
     }
   else if ((!active) && (mi->active))
     {
        tmp = _e_active_menus_copy_ref();
        mi->active = 0;
        _e_prev_active_menu_item = mi;
        _e_active_menu_item = NULL;
        if (mi->bg_object)
          edje_object_signal_emit(mi->bg_object, "e,state,unselected", "e");
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,unselected", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,unselected", "e");
        if (isedje(mi->submenu_object))
          edje_object_signal_emit(mi->submenu_object, "e,state,unselected", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,unselected", "e");
        if (mi->icon_key)
          {
             if (mi->icon_object)
               {
                  if (isedje(mi->icon_object))
                    edje_object_signal_emit(mi->icon_object, "e,state,unselected", "e");
                  else
                    e_icon_selected_set(mi->icon_object, EINA_FALSE);
               }
          }
        edje_object_signal_emit(mi->menu->bg_object, "e,state,unselected", "e");
     }
   _e_menu_list_free_unref(tmp);
}

E_API E_Menu_Item *
e_menu_item_active_get(void)
{
   return _e_active_menu_item;
}

E_API void
e_menu_active_item_activate(void)
{
   _e_menu_active_call();
   _e_menu_deactivate_all();
}

E_API void
e_menu_item_disabled_set(E_Menu_Item *mi, int disable)
{
   E_OBJECT_CHECK(mi);
   E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
   if (mi->separator) return;
   if ((disable))
     {
        if (mi->active) e_menu_item_active_set(mi, 0);
        mi->disable = 1;
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,disable", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,disable", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,disable", "e");
     }
   else
     {
        mi->disable = 0;
        if (mi->icon_bg_object)
          edje_object_signal_emit(mi->icon_bg_object, "e,state,enable", "e");
        if (isedje(mi->label_object))
          edje_object_signal_emit(mi->label_object, "e,state,enable", "e");
        if (isedje(mi->toggle_object))
          edje_object_signal_emit(mi->toggle_object, "e,state,enable", "e");
     }
}

E_API void
e_menu_idler_before(void)
{
   /* when e goes "idle" this gets called so leave all our hard work till */
   /* idle time to avoid falling behind the user. just evaluate the high */
   /* level state machine */
   Eina_List *l, *removals = NULL, *tmp;
   E_Menu *m;

   if (pending_feed)
     {
        e_comp_canvas_feed_mouse_up(pending_activate_time);
        pending_feed = 0;
     }

   /* add refcount to all menus we will work with */
   tmp = _e_active_menus_copy_ref();
   /* phase 1. hide all the menus that want to be hidden */
   EINA_LIST_FOREACH(_e_active_menus, l, m)
     {
        if ((!m->cur.visible) && (m->prev.visible))
          {
             m->prev.visible = m->cur.visible;
             e_object_ref(E_OBJECT(m));
             evas_object_pass_events_set(m->comp_object, 1);
             if (m->container_object)
               {
                  evas_object_intercept_move_callback_del(m->container_object, _e_menu_cb_intercept_container_move);
                  evas_object_intercept_resize_callback_del(m->container_object, _e_menu_cb_intercept_container_resize);
               }
             evas_object_hide(m->comp_object);
          }
     }
   /* phase 2. move & reisze all the menus that want to moves/resized */
   EINA_LIST_FOREACH(_e_active_menus, l, m)
     {
        if (m->frozen || (!m->active)) continue;
        if (!m->realized) _e_menu_realize(m);
        if (!m->realized) continue;
        if (((m->cur.w) != (m->prev.w)) ||
            ((m->cur.h) != (m->prev.h)))
          {
             int w, h;

             m->prev.w = m->cur.w;
             m->prev.h = m->cur.h;
             w = m->cur.w;
             h = m->cur.h;
             evas_object_resize(m->comp_object, w, h);
          }
        if (((m->cur.x) != (m->prev.x)) ||
            ((m->cur.y) != (m->prev.y)))
          {
             if (!m->parent_item)
               {
                  int x, y, w, h;

                  e_zone_useful_geometry_get(m->zone, &x, &y, &w, &h);
                  if (m->cur.w <= w)
                    {
                       if ((m->cur.x + m->cur.w) > (x + w))
                         m->cur.x = x + w - m->cur.w;
                    }
                  if (m->cur.h <= h)
                    {
                       if ((m->cur.y + m->cur.h) > (y + h))
                         m->cur.y = y + h - m->cur.h;
                    }
               }
             m->prev.x = m->cur.x;
             m->prev.y = m->cur.y;
             _e_menu_lock = 1;
             evas_object_move(m->comp_object, m->cur.x, m->cur.y);
             _e_menu_lock = 0;
          }
     }
   /* phase 3. show all the menus that want to be shown */
   EINA_LIST_FOREACH(_e_active_menus, l, m)
     {
        if (m->frozen) continue;
        if (!m->realized) continue;
        if (m->cur.visible)
          {
             m->prev.visible = m->cur.visible;
             evas_object_pass_events_set(m->comp_object, 0);
             evas_object_show(m->comp_object);
          }
     }
   /* phase 4. de-activate... */
   EINA_LIST_REVERSE_FOREACH(_e_active_menus, l, m)
     {
        if ((!m->active) && (!evas_object_visible_get(m->comp_object)))
          {
             _e_menu_unrealize(m);
             removals = eina_list_append(removals, m);
          }
     }
   EINA_LIST_FREE(removals, m)
     {
        if (m->in_active_list)
          {
             _e_active_menus = eina_list_remove(_e_active_menus, m);
             m->in_active_list = 0;
             e_object_unref(E_OBJECT(m));
          }
     }
   /* del refcount to all menus we worked with */
   _e_menu_list_free_unref(tmp);

   if (!_e_active_menus)
     {
        if (_e_menu_win == e_comp->ee_win)
          {
             e_comp_ungrab_input(1, 1);
             _e_menu_win = UINT_MAX;
             e_bindings_disabled_set(0);
          }
     }
}

E_API Eina_Bool
e_menu_is_active(void)
{
   return _e_menu_win == e_comp->ee_win;
}

E_API E_Menu *
e_menu_active_get(void)
{
   return _e_active_menus ? eina_list_last_data_get(_e_active_menus) : NULL;
}

/* local subsystem functions */
static void
_e_menu_dangling_cb(void *data)
{
   E_Menu *m = data;
   
   WRN("DANGLING SUBMENU: REF(%d)||MENU(%p)", e_object_ref_get(data), data);
   m->dangling_job = NULL;
}

static void
_e_menu_free(E_Menu *m)
{
   Eina_List *l, *l_next;
   E_Menu_Item *mi;
   E_Menu_Category *cat = NULL;

   /* the foreign menu items */
   if (m->category) cat = eina_hash_find(_e_menu_categories, m->category);
   if (cat)
     {
        E_Menu_Category_Callback *cb;

        EINA_LIST_FOREACH(cat->callbacks, l, cb)
          {
             if (cb->free) cb->free(cb->data);
          }
     }
   eina_stringshare_replace(&m->category, NULL);
   if (m->parent_item)
     m->parent_item->submenu = NULL;
   _e_menu_unrealize(m);
   if (m->realized) return;
   EINA_LIST_FOREACH_SAFE(m->items, l, l_next, mi)
     e_object_del(E_OBJECT(mi));
   if (m->in_active_list)
     {
        _e_active_menus = eina_list_remove(_e_active_menus, m);
        m->in_active_list = 0;
     }
   if (m->header.title) eina_stringshare_del(m->header.title);
   if (m->header.icon_file) eina_stringshare_del(m->header.icon_file);
   if (m->dangling_job) ecore_job_del(m->dangling_job);
   free(m);
}

static void
_e_menu_item_free(E_Menu_Item *mi)
{
   if (mi == _e_active_menu_item) _e_active_menu_item = NULL;
   if (mi == _e_prev_active_menu_item) _e_prev_active_menu_item = NULL;
   if (mi->submenu)
     {
        int ref = 0;

        /* parent_item gets unset in a few places, reapply it for use in cleanup */
        if (!mi->submenu->parent_item)
          mi->submenu->parent_item = mi;
        /* menu may not have been deactivated, ensure deactivate callback is called */
        if (mi->active)
          _e_menu_submenu_deactivate(mi);
        /* submenus CANNOT exist without their parent menu+item, so ensure that they get deleted */
        if (mi->submenu)
          {
             ref = e_object_ref_get(E_OBJECT(mi->submenu)) - 1;
             e_object_unref(E_OBJECT(mi->submenu));
          }
        if (ref)
          {
             if (!mi->submenu->dangling_job)
               mi->submenu->dangling_job = ecore_job_add(_e_menu_dangling_cb, mi->submenu);
             mi->submenu->parent_item = NULL;
          }
     }
   if (mi->menu->realized) _e_menu_item_unrealize(mi);
   mi->menu->items = eina_list_remove(mi->menu->items, mi);
   if (mi->icon) eina_stringshare_del(mi->icon);
   if (mi->icon_key) eina_stringshare_del(mi->icon_key);
   if (mi->label) eina_stringshare_del(mi->label);
   free(mi);
}

static void
_e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
{
   E_Menu_Item *mi;

   mi = data;
   mi->x = x;
   mi->y = y;
   evas_object_move(o, x, y);
   if ((mi->submenu) && (mi->submenu->parent_item))
     {
        mi->submenu->zone = mi->menu->zone;
        _e_menu_reposition(mi->submenu);
     }
}

static void
_e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
   E_Menu_Item *mi;

   mi = data;
   mi->w = w;
   mi->h = h;
   evas_object_resize(o, w, h);
   if ((mi->submenu) && (mi->submenu->parent_item))
     _e_menu_reposition(mi->submenu);
}

static void
_e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
{
   E_Menu *m;

   m = data;
   m->container_x = x;
   m->container_y = y;
   if (m->parent_item) _e_menu_reposition(m);
   evas_object_move(o, x, y);
}

static void
_e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
   E_Menu *m;

   m = data;
   m->container_w = w;
   m->container_h = h;
   if (m->parent_item) _e_menu_reposition(m);
   evas_object_resize(o, w, h);
}

static void
_e_menu_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   e_object_unref(data);
}

static void
_e_menu_item_realize(E_Menu_Item *mi)
{
   Evas_Object *o;
   Evas_Coord ww = 1, hh = 1;

   /* and set up initial item state */
   if (mi->separator)
     {
        o = edje_object_add(mi->menu->evas);
        mi->separator_object = o;
        e_theme_edje_object_set(o, "base/theme/menus",
                                "e/widgets/menu/default/separator");
        evas_object_show(o);
        edje_object_size_min_calc(mi->separator_object, &ww, &hh);
        E_FILL(mi->separator_object);
        mi->separator_w = ww;
        mi->separator_h = hh;
        elm_box_pack_end(mi->menu->container_object, mi->separator_object);
     }
   else
     {
        o = edje_object_add(mi->menu->evas);
        mi->bg_object = o;
        evas_object_name_set(o, "mi->bg_object");
        evas_object_data_set(o, "e_menu_item", mi);
        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN, _e_menu_cb_item_in, mi);
        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT, _e_menu_cb_item_out, mi);
        evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_item_move, mi);
        evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_item_resize, mi);
        if ((mi->submenu) || (mi->submenu_pre_cb.func))
          {
             if (!e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
                                          "e/widgets/menu/default/submenu_bg"))
               goto no_submenu_item;
          }
        else
          {
no_submenu_item:
             e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
                                     "e/widgets/menu/default/item_bg");
          }
        evas_object_show(o);

        o = elm_box_add(e_comp->elm);
        evas_object_name_set(o, "mi->container_object");
        elm_box_homogeneous_set(o, 0);
        mi->container_object = o;
        elm_box_horizontal_set(o, 1);
        evas_object_show(o);


        if (mi->check)
          {
             o = edje_object_add(mi->menu->evas);
             evas_object_name_set(o, "mi->toggle_object");
             mi->toggle_object = o;
             e_theme_edje_object_set(o, "base/theme/menus",
                                     "e/widgets/menu/default/check");
             evas_object_show(o);
             elm_box_pack_end(mi->container_object, o);
             edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
             mi->toggle_w = ww;
             mi->toggle_h = hh;
             E_WEIGHT(mi->toggle_object, 0, 1);
             E_FILL(mi->toggle_object);
             evas_object_size_hint_min_set(mi->toggle_object, ww, hh);
          }
        else if (mi->radio)
          {
             o = edje_object_add(mi->menu->evas);
             evas_object_name_set(o, "mi->toggle_object");
             mi->toggle_object = o;
             e_theme_edje_object_set(o, "base/theme/menus",
                                     "e/widgets/menu/default/radio");
             evas_object_show(o);
             elm_box_pack_end(mi->container_object, o);
             edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
             mi->toggle_w = ww;
             mi->toggle_h = hh;
             E_WEIGHT(mi->toggle_object, 0, 1);
             E_FILL(mi->toggle_object);
             evas_object_size_hint_min_set(mi->toggle_object, ww, hh);
          }
        else
          {
             o = evas_object_rectangle_add(mi->menu->evas);
             evas_object_name_set(o, "mi->toggle_object");
             mi->toggle_object = o;
             evas_object_color_set(o, 0, 0, 0, 0);
             elm_box_pack_end(mi->container_object, o);
          }
        if ((!e_config->menu_icons_hide) && ((mi->icon) || (mi->realize_cb.func)))
          {
             int icon_w = 0, icon_h = 0;

             o = edje_object_add(mi->menu->evas);
             if (e_theme_edje_object_set(o, "base/theme/menus",
                                         "e/widgets/menu/default/icon"))
               {
                  evas_object_name_set(o, "mi->icon_bg_object");
                  mi->icon_bg_object = o;
                  evas_object_show(o);
               }
             else
               {
                  evas_object_del(o);
                  o = NULL;
               }
             //if (o) evas_object_pass_events_set(o, 1);

             /* FIXME: Not sure why there are two different tries to get the icon size, surely only the last one is needed. */
             /* FIXME: Do it this way later, when e_app_icon_add() just registers a request for an icon to be filled in when it's ready.
                if (mi->app)
                {
                  o = e_app_icon_add(mi->menu->evas, mi->app);