@@ -95,13 +95,21 @@ 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+         self .g_directories  =  []
104107        self .custom_modules  =  {}
108+         if  self .type  ==  "applet" : changed_key  =  "enabled-applets" 
109+         elif  self .type  ==  "desklet" : changed_key  =  "enabled-desklets" 
110+         else : changed_key  =  None 
111+         if  changed_key :
112+             self .gsettings .connect ("changed::"  +  changed_key , lambda  * args : self .on_enabled_xlets_changed (changed_key , * args ))
105113
106114        self .load_xlet_data ()
107115        self .build_window ()
@@ -128,7 +136,7 @@ def _on_proxy_ready (self, obj, result, data=None):
128136            proxy  =  None 
129137
130138        if  proxy :
131-             proxy . highlightXlet ( '(ssb)' ,  self .uuid ,  self . selected_instance [ "id" ] , True )
139+             self . highlight_xlet ( self .selected_instance , True )
132140
133141    def  load_xlet_data  (self ):
134142        self .xlet_dir  =  "/usr/share/cinnamon/%ss/%s"  %  (self .type , self .uuid )
@@ -242,18 +250,22 @@ def check_sizing(widget, data=None):
242250        self .next_button .connect ("clicked" , self .next_instance )
243251
244252    def  load_instances (self ):
245-         self .instance_info  =  []
246253        path  =  Path (os .path .join (settings_dir , self .uuid ))
247254        old_path  =  Path ("%s/.cinnamon/configs/%s"  %  (home , self .uuid ))
248-         instances  =  0 
255+         for  p  in  path , old_path :
256+             if  not  p .exists (): continue 
257+             self .g_directories .append (Gio .File .new_for_path (str (p )))
258+ 
249259        new_items  =  os .listdir (path ) if  path .exists () else  []
250260        old_items  =  os .listdir (old_path ) if  old_path .exists () else  []
251261        dir_items  =  sorted (new_items  +  old_items )
262+ 
252263        try :
253264            multi_instance  =  int (self .xlet_meta ["max-instances" ]) !=  1 
254265        except  (KeyError , ValueError ):
255266            multi_instance  =  False 
256267
268+         enabled  =  [x .split (":" ) for  x  in  self .gsettings .get_strv ('enabled-%ss'  %  self .type )]
257269        for  item  in  dir_items :
258270            # ignore anything that isn't json 
259271            if  item [- 5 :] !=  ".json" :
@@ -271,66 +283,82 @@ def load_instances(self):
271283                    continue  # multi-instance should have file names of the form [instance-id].json 
272284
273285                instance_exists  =  False 
274-                 enabled  =  self .gsettings .get_strv ('enabled-%ss'  %  self .type )
275286                for  definition  in  enabled :
276-                     if  self .uuid  in  definition  and  instance_id  in  definition . split ( ':' ) :
287+                     if  self .uuid  in  definition  and  instance_id  in  definition :
277288                        instance_exists  =  True 
278289                        break 
279290
280291                if  not  instance_exists :
281292                    continue 
282293
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 )
294+             config_path  =  os .path .join (path  if  item  in  new_items  else  old_path , item )
295+             self .create_settings_page (config_path )
296+ 
297+         if  not  self .instance_info :
298+             print (f"No instances were found for { self .uuid }  )
299+             sys .exit ()
300+ 
301+         self .next_button .set_no_show_all (True )
302+         self .prev_button .set_no_show_all (True )
303+         self .show_prev_next_buttons () if  self .has_multiple_instances () else  self .hide_prev_next_buttons ()
304+ 
305+     def  create_settings_page (self , config_path ):
306+         instance_id  =  os .path .basename (config_path )[:- 5 ]
307+         if  self .instance_stack .get_child_by_name (instance_id ) is  not None : return 
308+         settings  =  JSONSettingsHandler (config_path , self .notify_dbus )
309+         settings .instance_id  =  instance_id 
310+         instance_box  =  Gtk .Box (orientation = Gtk .Orientation .VERTICAL )
311+         self .instance_stack .add_named (instance_box , instance_id )
312+         info  =  {"settings" : settings , "id" : instance_id }
313+         self .instance_info .append (info )
314+         settings_map  =  settings .get_settings ()
315+         first_key  =  next (iter (settings_map .values ()))
290316
291-             settings_map  =  settings .get_settings ()
292-             first_key  =  next (iter (settings_map .values ()))
317+         try :
318+             for  setting  in  settings_map :
319+                 if  setting  ==  "__md5__" :
320+                     continue 
321+                 for  key  in  settings_map [setting ]:
322+                     if  key  in  ("description" , "tooltip" , "units" ):
323+                         try :
324+                             settings_map [setting ][key ] =  translate (self .uuid , settings_map [setting ][key ])
325+                         except  (KeyError , ValueError ):
326+                             traceback .print_exc ()
327+                     elif  key  in  "options" :
328+                         new_opt_data  =  collections .OrderedDict ()
329+                         opt_data  =  settings_map [setting ][key ]
330+                         for  option  in  opt_data :
331+                             if  opt_data [option ] ==  "custom" :
332+                                 continue 
333+                             new_opt_data [translate (self .uuid , option )] =  opt_data [option ]
334+                         settings_map [setting ][key ] =  new_opt_data 
335+                     elif  key  in  "columns" :
336+                         columns_data  =  settings_map [setting ][key ]
337+                         for  column  in  columns_data :
338+                             column ["title" ] =  translate (self .uuid , column ["title" ])
339+         finally :
340+             # if a layout is not explicitly defined, generate the settings 
341+             # widgets based on the order they occur 
342+             if  first_key ["type" ] ==  "layout" :
343+                 self .build_with_layout (settings_map , info , instance_box , first_key )
344+             else :
345+                 self .build_from_order (settings_map , info , instance_box , first_key )
293346
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 )
347+             if  self .selected_instance  is  None :
348+                 self .selected_instance  =  info 
349+                 if  "stack"  in  info :
350+                     self .stack_switcher .set_stack (info ["stack" ])
323351
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" ])
352+     def  has_multiple_instances (self ):
353+         return  len (self .instance_info ) >  1 
328354
329-             instances  +=  1 
355+     def  hide_prev_next_buttons (self ):
356+         self .prev_button .hide ()
357+         self .next_button .hide ()
330358
331-          if   instances   <   2 :
332-              self .prev_button .set_no_show_all ( True )
333-              self .next_button .set_no_show_all ( True )
359+     def   show_prev_next_buttons ( self ) :
360+         self .prev_button .show ( )
361+         self .next_button .show ( )
334362
335363    def  build_with_layout (self , settings_map , info , box , first_key ):
336364        layout  =  first_key 
@@ -460,26 +488,95 @@ def set_instance(self, info):
460488                else :
461489                    info ["stack" ].set_visible_child (children [0 ])
462490        if  proxy :
463-             proxy .highlightXlet ('(ssb)' , self .uuid , self .selected_instance ["id" ], False )
464-             proxy .highlightXlet ('(ssb)' , self .uuid , info ["id" ], True )
491+             old_info  =  self .selected_instance 
492+             new_info  =  info 
493+             self .highlight_xlet (old_info , False )
494+             self .highlight_xlet (new_info , True )
465495        self .selected_instance  =  info 
466496
497+     def  highlight_xlet (self , info , highlighted ):
498+         try :
499+             proxy .highlightXlet ('(ssb)' , self .uuid , info ["id" ], highlighted )
500+         except :
501+             return 
502+ 
467503    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 ])
504+         self .get_next_instance (False )
471505
472506    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 ])
507+         self .get_next_instance ()
508+ 
509+     def  get_next_instance (self , positive_direction  =  True ):
510+         transition  =  Gtk .StackTransitionType .OVER_LEFT  if  positive_direction  else  Gtk .StackTransitionType .OVER_RIGHT 
511+         self .instance_stack .set_transition_type (transition )
512+         step  =  1  if  positive_direction  else  - 1 
513+         instances_length  =  len (self .instance_info )
514+         start  =  self .instance_info .index (self .selected_instance )
515+         nextIndex  =  (start  +  step ) %  instances_length 
516+         self .set_instance (self .instance_info [nextIndex ])
517+ 
518+     def  on_enabled_xlets_changed (self , key , * args ):
519+         """ 
520+         Args: 
521+             key ("enabled-applets"|"enabled-desklets") 
522+         """ 
523+         current_ids  =  {info ["id" ] for  info  in  self .instance_info }
524+         new_ids  =  set ()
525+         for  definition  in  self .gsettings .get_strv (key ):
526+             definition  =  definition .split (":" )
527+             uuid , instance_id  =  (definition [- 2 ], definition [- 1 ]) if  key  ==  "enabled-applets" \
528+                 else  (definition [0 ], definition [1 ])
529+             if  uuid  !=  self .uuid : continue 
530+             new_ids .add (instance_id )
531+         added_ids  =  new_ids  -  current_ids 
532+ 
533+         removed_indices  =  []
534+         selected_removed_index  =  - 1 
535+         for  i , info  in  enumerate (self .instance_info ):
536+             if  info ["id" ] in  new_ids : continue 
537+             removed_indices .append (i )
538+             if  info  ==  self .selected_instance : selected_removed_index  =  i 
539+ 
540+         if  len (current_ids ) +  len (added_ids ) ==  len (removed_indices ):
541+             self .quit ()
542+             return 
543+ 
544+         for  id  in  added_ids :
545+             for  dir  in  self .g_directories :
546+                 file  =  dir .get_child (id  +  ".json" )
547+                 if  file .query_exists (None ):
548+                     self .create_new_settings_page (file .get_path ())
549+                     continue 
550+                 # Config files have not been added yet, need to monitor directories 
551+                 monitor  =  dir .monitor_directory (Gio .FileMonitorFlags .NONE , None )
552+                 monitor .connect ("changed" , self .on_config_file_added )
553+                 self .monitors .setdefault (id , []).append (monitor )
554+ 
555+         if  (selected_removed_index  !=  - 1 ):
556+             self .get_next_instance ()
557+ 
558+         for  index  in  sorted (removed_indices , reverse = True ):
559+             self .monitors .get (self .instance_info [index ]["id" ], []).clear ()
560+             self .instance_stack .remove (self .instance_stack .get_child_by_name (self .instance_info [index ]["id" ]))
561+             self .instance_info .pop (index )
480562
481-     # def unpack_args(self, args): 
482-     #    args = {} 
563+         if  not  self .has_multiple_instances (): self .hide_prev_next_buttons ()
564+ 
565+     def  on_config_file_added (self , * args ):
566+         file , event_type  =  args [1 ], args [- 1 ]
567+         instance  =  file .get_basename ()[:- 5 ]
568+         if  event_type  !=  Gio .FileMonitorEvent .CHANGES_DONE_HINT  : return 
569+         if  instance  not  in self .monitors : return 
570+         for  monitor  in  self .monitors [instance ]: monitor .cancel ()
571+         del  self .monitors [instance ]
572+         self .create_new_settings_page (file .get_path ())
573+ 
574+ 
575+     def  create_new_settings_page (self , path ):
576+         self .create_settings_page (path )
577+         self .window .show_all ()
578+         if  self .has_multiple_instances (): self .show_prev_next_buttons ()
579+         self .highlight_xlet (self .selected_instance , True )
483580
484581    def  backup (self , * args ):
485582        dialog  =  Gtk .FileChooserDialog (_ ("Select or enter file to export to" ),
@@ -531,8 +628,7 @@ def reload_xlet(self, *args):
531628
532629    def  quit (self , * args ):
533630        if  proxy :
534-             proxy .highlightXlet ('(ssb)' , self .uuid , self .selected_instance ["id" ], False )
535- 
631+             self .highlight_xlet (self .selected_instance , False )
536632        self .window .destroy ()
537633        Gtk .main_quit ()
538634
0 commit comments