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