@@ -95,12 +95,17 @@ def __init__(self, args):
95
95
self .type = args .type
96
96
self .uuid = args .uuid
97
97
self .tab = 0
98
+ self .instance_info = []
98
99
self .instance_id = str (args .id )
99
100
if args .tab is not None :
100
101
self .tab = int (args .tab )
101
102
102
103
self .selected_instance = None
103
104
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 = []
104
109
self .custom_modules = {}
105
110
106
111
self .load_xlet_data ()
@@ -128,7 +133,7 @@ def _on_proxy_ready (self, obj, result, data=None):
128
133
proxy = None
129
134
130
135
if proxy :
131
- proxy . highlightXlet ( '(ssb)' , self .uuid , self . selected_instance [ "id" ] , True )
136
+ self . highlight_xlet ( self .selected_instance , True )
132
137
133
138
def load_xlet_data (self ):
134
139
self .xlet_dir = "/usr/share/cinnamon/%ss/%s" % (self .type , self .uuid )
@@ -242,18 +247,22 @@ def check_sizing(widget, data=None):
242
247
self .next_button .connect ("clicked" , self .next_instance )
243
248
244
249
def load_instances (self ):
245
- self .instance_info = []
246
250
path = Path (os .path .join (settings_dir , self .uuid ))
247
251
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
+
249
256
new_items = os .listdir (path ) if path .exists () else []
250
257
old_items = os .listdir (old_path ) if old_path .exists () else []
251
258
dir_items = sorted (new_items + old_items )
259
+
252
260
try :
253
261
multi_instance = int (self .xlet_meta ["max-instances" ]) != 1
254
262
except (KeyError , ValueError ):
255
263
multi_instance = False
256
264
265
+ enabled = [x .split (":" ) for x in self .gsettings .get_strv ('enabled-%ss' % self .type )]
257
266
for item in dir_items :
258
267
# ignore anything that isn't json
259
268
if item [- 5 :] != ".json" :
@@ -271,66 +280,82 @@ def load_instances(self):
271
280
continue # multi-instance should have file names of the form [instance-id].json
272
281
273
282
instance_exists = False
274
- enabled = self .gsettings .get_strv ('enabled-%ss' % self .type )
275
283
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 :
277
285
instance_exists = True
278
286
break
279
287
280
288
if not instance_exists :
281
289
continue
282
290
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 ()))
290
313
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 )
293
343
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" ])
323
348
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
328
351
329
- instances += 1
352
+ def hide_prev_next_buttons (self ):
353
+ self .prev_button .hide ()
354
+ self .next_button .hide ()
330
355
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 ( )
334
359
335
360
def build_with_layout (self , settings_map , info , box , first_key ):
336
361
layout = first_key
@@ -460,26 +485,95 @@ def set_instance(self, info):
460
485
else :
461
486
info ["stack" ].set_visible_child (children [0 ])
462
487
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 )
465
492
self .selected_instance = info
466
493
494
+ def highlight_xlet (self , info , highlighted ):
495
+ try :
496
+ proxy .highlightXlet ('(ssb)' , self .uuid , info ["id" ], highlighted )
497
+ except :
498
+ return
499
+
467
500
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 )
471
502
472
503
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 )
480
559
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 )
483
577
484
578
def backup (self , * args ):
485
579
dialog = Gtk .FileChooserDialog (_ ("Select or enter file to export to" ),
@@ -531,8 +625,7 @@ def reload_xlet(self, *args):
531
625
532
626
def quit (self , * args ):
533
627
if proxy :
534
- proxy .highlightXlet ('(ssb)' , self .uuid , self .selected_instance ["id" ], False )
535
-
628
+ self .highlight_xlet (self .selected_instance , False )
536
629
self .window .destroy ()
537
630
Gtk .main_quit ()
538
631
0 commit comments