@@ -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 } . Exiting..." )
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