@@ -95,12 +95,17 @@ def __init__(self, args):
9595        self .type  =  args .type 
9696        self .uuid  =  args .uuid 
9797        self .tab  =  0 
98+         self .instance_info  =  []
9899        self .instance_id  =  str (args .id )
99100        if  args .tab  is  not None :
100101            self .tab  =  int (args .tab )
101102
102103        self .selected_instance  =  None 
103104        self .gsettings  =  Gio .Settings .new ("org.cinnamon" )
105+         self .monitors  =  {}
106+         changed_key  =  "enabled-applets"  if  self .type  ==  "applet"  else  "enabled-desklets" 
107+         self .gsettings .connect ("changed::"  +  changed_key , lambda  * args : self .on_enabled_xlets_changed (changed_key , * args ))
108+         self .g_directories  =  []
104109        self .custom_modules  =  {}
105110
106111        self .load_xlet_data ()
@@ -128,7 +133,7 @@ def _on_proxy_ready (self, obj, result, data=None):
128133            proxy  =  None 
129134
130135        if  proxy :
131-             proxy . highlightXlet ( '(ssb)' ,  self .uuid ,  self . selected_instance [ "id" ] , True )
136+             self . highlight_xlet ( self .selected_instance , True )
132137
133138    def  load_xlet_data  (self ):
134139        self .xlet_dir  =  "/usr/share/cinnamon/%ss/%s"  %  (self .type , self .uuid )
@@ -242,18 +247,22 @@ def check_sizing(widget, data=None):
242247        self .next_button .connect ("clicked" , self .next_instance )
243248
244249    def  load_instances (self ):
245-         self .instance_info  =  []
246250        path  =  Path (os .path .join (settings_dir , self .uuid ))
247251        old_path  =  Path ("%s/.cinnamon/configs/%s"  %  (home , self .uuid ))
248-         instances  =  0 
252+         for  p  in  path , old_path :
253+             if  not  p .exists (): continue 
254+             self .g_directories .append (Gio .File .new_for_path (str (p )))
255+ 
249256        new_items  =  os .listdir (path ) if  path .exists () else  []
250257        old_items  =  os .listdir (old_path ) if  old_path .exists () else  []
251258        dir_items  =  sorted (new_items  +  old_items )
259+ 
252260        try :
253261            multi_instance  =  int (self .xlet_meta ["max-instances" ]) !=  1 
254262        except  (KeyError , ValueError ):
255263            multi_instance  =  False 
256264
265+         enabled  =  [x .split (":" ) for  x  in  self .gsettings .get_strv ('enabled-%ss'  %  self .type )]
257266        for  item  in  dir_items :
258267            # ignore anything that isn't json 
259268            if  item [- 5 :] !=  ".json" :
@@ -271,66 +280,82 @@ def load_instances(self):
271280                    continue  # multi-instance should have file names of the form [instance-id].json 
272281
273282                instance_exists  =  False 
274-                 enabled  =  self .gsettings .get_strv ('enabled-%ss'  %  self .type )
275283                for  definition  in  enabled :
276-                     if  self .uuid  in  definition  and  instance_id  in  definition . split ( ':' ) :
284+                     if  self .uuid  in  definition  and  instance_id  in  definition :
277285                        instance_exists  =  True 
278286                        break 
279287
280288                if  not  instance_exists :
281289                    continue 
282290
283-             settings  =  JSONSettingsHandler (os .path .join (path  if  item  in  new_items  else  old_path , item ), self .notify_dbus )
284-             settings .instance_id  =  instance_id 
285-             instance_box  =  Gtk .Box (orientation = Gtk .Orientation .VERTICAL )
286-             self .instance_stack .add_named (instance_box , instance_id )
287- 
288-             info  =  {"settings" : settings , "id" : instance_id }
289-             self .instance_info .append (info )
291+             config_path  =  os .path .join (path  if  item  in  new_items  else  old_path , item )
292+             self .create_settings_page (config_path )
293+ 
294+         if  not  self .instance_info :
295+             print (f"No instances were found for { self .uuid }  )
296+             sys .exit ()
297+ 
298+         self .next_button .set_no_show_all (True )
299+         self .prev_button .set_no_show_all (True )
300+         self .show_prev_next_buttons () if  self .has_multiple_instances () else  self .hide_prev_next_buttons ()
301+ 
302+     def  create_settings_page (self , config_path ):
303+         instance_id  =  os .path .basename (config_path )[:- 5 ]
304+         if  self .instance_stack .get_child_by_name (instance_id ) is  not None : return 
305+         settings  =  JSONSettingsHandler (config_path , self .notify_dbus )
306+         settings .instance_id  =  instance_id 
307+         instance_box  =  Gtk .Box (orientation = Gtk .Orientation .VERTICAL )
308+         self .instance_stack .add_named (instance_box , instance_id )
309+         info  =  {"settings" : settings , "id" : instance_id }
310+         self .instance_info .append (info )
311+         settings_map  =  settings .get_settings ()
312+         first_key  =  next (iter (settings_map .values ()))
290313
291-             settings_map  =  settings .get_settings ()
292-             first_key  =  next (iter (settings_map .values ()))
314+         try :
315+             for  setting  in  settings_map :
316+                 if  setting  ==  "__md5__" :
317+                     continue 
318+                 for  key  in  settings_map [setting ]:
319+                     if  key  in  ("description" , "tooltip" , "units" ):
320+                         try :
321+                             settings_map [setting ][key ] =  translate (self .uuid , settings_map [setting ][key ])
322+                         except  (KeyError , ValueError ):
323+                             traceback .print_exc ()
324+                     elif  key  in  "options" :
325+                         new_opt_data  =  collections .OrderedDict ()
326+                         opt_data  =  settings_map [setting ][key ]
327+                         for  option  in  opt_data :
328+                             if  opt_data [option ] ==  "custom" :
329+                                 continue 
330+                             new_opt_data [translate (self .uuid , option )] =  opt_data [option ]
331+                         settings_map [setting ][key ] =  new_opt_data 
332+                     elif  key  in  "columns" :
333+                         columns_data  =  settings_map [setting ][key ]
334+                         for  column  in  columns_data :
335+                             column ["title" ] =  translate (self .uuid , column ["title" ])
336+         finally :
337+             # if a layout is not explicitly defined, generate the settings 
338+             # widgets based on the order they occur 
339+             if  first_key ["type" ] ==  "layout" :
340+                 self .build_with_layout (settings_map , info , instance_box , first_key )
341+             else :
342+                 self .build_from_order (settings_map , info , instance_box , first_key )
293343
294-             try :
295-                 for  setting  in  settings_map :
296-                     if  setting  ==  "__md5__" :
297-                         continue 
298-                     for  key  in  settings_map [setting ]:
299-                         if  key  in  ("description" , "tooltip" , "units" ):
300-                             try :
301-                                 settings_map [setting ][key ] =  translate (self .uuid , settings_map [setting ][key ])
302-                             except  (KeyError , ValueError ):
303-                                 traceback .print_exc ()
304-                         elif  key  in  "options" :
305-                             new_opt_data  =  collections .OrderedDict ()
306-                             opt_data  =  settings_map [setting ][key ]
307-                             for  option  in  opt_data :
308-                                 if  opt_data [option ] ==  "custom" :
309-                                     continue 
310-                                 new_opt_data [translate (self .uuid , option )] =  opt_data [option ]
311-                             settings_map [setting ][key ] =  new_opt_data 
312-                         elif  key  in  "columns" :
313-                             columns_data  =  settings_map [setting ][key ]
314-                             for  column  in  columns_data :
315-                                 column ["title" ] =  translate (self .uuid , column ["title" ])
316-             finally :
317-                 # if a layout is not explicitly defined, generate the settings 
318-                 # widgets based on the order they occur 
319-                 if  first_key ["type" ] ==  "layout" :
320-                     self .build_with_layout (settings_map , info , instance_box , first_key )
321-                 else :
322-                     self .build_from_order (settings_map , info , instance_box , first_key )
344+             if  self .selected_instance  is  None :
345+                 self .selected_instance  =  info 
346+                 if  "stack"  in  info :
347+                     self .stack_switcher .set_stack (info ["stack" ])
323348
324-                 if  self .selected_instance  is  None :
325-                     self .selected_instance  =  info 
326-                     if  "stack"  in  info :
327-                         self .stack_switcher .set_stack (info ["stack" ])
349+     def  has_multiple_instances (self ):
350+         return  len (self .instance_info ) >  1 
328351
329-             instances  +=  1 
352+     def  hide_prev_next_buttons (self ):
353+         self .prev_button .hide ()
354+         self .next_button .hide ()
330355
331-          if   instances   <   2 :
332-              self .prev_button .set_no_show_all ( True )
333-              self .next_button .set_no_show_all ( True )
356+     def   show_prev_next_buttons ( self ) :
357+         self .prev_button .show ( )
358+         self .next_button .show ( )
334359
335360    def  build_with_layout (self , settings_map , info , box , first_key ):
336361        layout  =  first_key 
@@ -460,26 +485,95 @@ def set_instance(self, info):
460485                else :
461486                    info ["stack" ].set_visible_child (children [0 ])
462487        if  proxy :
463-             proxy .highlightXlet ('(ssb)' , self .uuid , self .selected_instance ["id" ], False )
464-             proxy .highlightXlet ('(ssb)' , self .uuid , info ["id" ], True )
488+             old_info  =  self .selected_instance 
489+             new_info  =  info 
490+             self .highlight_xlet (old_info , False )
491+             self .highlight_xlet (new_info , True )
465492        self .selected_instance  =  info 
466493
494+     def  highlight_xlet (self , info , highlighted ):
495+         try :
496+             proxy .highlightXlet ('(ssb)' , self .uuid , info ["id" ], highlighted )
497+         except :
498+             return 
499+ 
467500    def  previous_instance (self , * args ):
468-         self .instance_stack .set_transition_type (Gtk .StackTransitionType .OVER_RIGHT )
469-         index  =  self .instance_info .index (self .selected_instance )
470-         self .set_instance (self .instance_info [index - 1 ])
501+         self .get_next_instance (False )
471502
472503    def  next_instance (self , * args ):
473-         self .instance_stack .set_transition_type (Gtk .StackTransitionType .OVER_LEFT )
474-         index  =  self .instance_info .index (self .selected_instance )
475-         if  index  ==  len (self .instance_info ) -  1 :
476-             index  =  0 
477-         else :
478-             index  += 1 
479-         self .set_instance (self .instance_info [index ])
504+         self .get_next_instance ()
505+ 
506+     def  get_next_instance (self , positive_direction  =  True ):
507+         transition  =  Gtk .StackTransitionType .OVER_LEFT  if  positive_direction  else  Gtk .StackTransitionType .OVER_RIGHT 
508+         self .instance_stack .set_transition_type (transition )
509+         step  =  1  if  positive_direction  else  - 1 
510+         instances_length  =  len (self .instance_info )
511+         start  =  self .instance_info .index (self .selected_instance )
512+         nextIndex  =  (start  +  step ) %  instances_length 
513+         self .set_instance (self .instance_info [nextIndex ])
514+ 
515+     def  on_enabled_xlets_changed (self , key , * args ):
516+         """ 
517+         Args: 
518+             key ("enabled-applets"|"enabled-desklets") 
519+         """ 
520+         current_ids  =  {info ["id" ] for  info  in  self .instance_info }
521+         new_ids  =  set ()
522+         for  definition  in  self .gsettings .get_strv (key ):
523+             definition  =  definition .split (":" )
524+             uuid , instance_id  =  (definition [- 2 ], definition [- 1 ]) if  key  ==  "enabled-applets" \
525+                 else  (definition [0 ], definition [1 ])
526+             if  uuid  !=  self .uuid : continue 
527+             new_ids .add (instance_id )
528+         added_ids  =  new_ids  -  current_ids 
529+ 
530+         removed_indices  =  []
531+         selected_removed_index  =  - 1 
532+         for  i , info  in  enumerate (self .instance_info ):
533+             if  info ["id" ] in  new_ids : continue 
534+             removed_indices .append (i )
535+             if  info  ==  self .selected_instance : selected_removed_index  =  i 
536+ 
537+         if  len (current_ids ) +  len (added_ids ) ==  len (removed_indices ):
538+             self .quit ()
539+             return 
540+ 
541+         for  id  in  added_ids :
542+             for  dir  in  self .g_directories :
543+                 file  =  dir .get_child (id  +  ".json" )
544+                 if  file .query_exists (None ):
545+                     self .create_new_settings_page (file .get_path ())
546+                     continue 
547+                 # Config files have not been added yet, need to monitor directories 
548+                 monitor  =  dir .monitor_directory (Gio .FileMonitorFlags .NONE , None )
549+                 monitor .connect ("changed" , self .on_config_file_added )
550+                 self .monitors .setdefault (id , []).append (monitor )
551+ 
552+         if  (selected_removed_index  !=  - 1 ):
553+             self .get_next_instance ()
554+ 
555+         for  index  in  sorted (removed_indices , reverse = True ):
556+             self .monitors .get (self .instance_info [index ]["id" ], []).clear ()
557+             self .instance_stack .remove (self .instance_stack .get_child_by_name (self .instance_info [index ]["id" ]))
558+             self .instance_info .pop (index )
480559
481-     # def unpack_args(self, args): 
482-     #    args = {} 
560+         if  not  self .has_multiple_instances (): self .hide_prev_next_buttons ()
561+ 
562+     def  on_config_file_added (self , * args ):
563+         file , event_type  =  args [1 ], args [- 1 ]
564+         instance  =  file .get_basename ()[:- 5 ]
565+         if  event_type  !=  Gio .FileMonitorEvent .CHANGES_DONE_HINT  : return 
566+         if  instance  not  in self .monitors : return 
567+         for  monitor  in  self .monitors [instance ]: monitor .cancel ()
568+         del  self .monitors [instance ]
569+         self .create_new_settings_page (file .get_path ())
570+ 
571+ 
572+     def  create_new_settings_page (self , path ):
573+         self .create_settings_page (path )
574+         self .window .show_all ()
575+         if  self .has_multiple_instances (): self .show_prev_next_buttons ()
576+         self .highlight_xlet (self .selected_instance , True )
483577
484578    def  backup (self , * args ):
485579        dialog  =  Gtk .FileChooserDialog (_ ("Select or enter file to export to" ),
@@ -531,8 +625,7 @@ def reload_xlet(self, *args):
531625
532626    def  quit (self , * args ):
533627        if  proxy :
534-             proxy .highlightXlet ('(ssb)' , self .uuid , self .selected_instance ["id" ], False )
535- 
628+             self .highlight_xlet (self .selected_instance , False )
536629        self .window .destroy ()
537630        Gtk .main_quit ()
538631
0 commit comments