diff --git a/glass-components/glass_components/components.py b/glass-components/glass_components/components.py index 9266b56..51024e7 100644 --- a/glass-components/glass_components/components.py +++ b/glass-components/glass_components/components.py @@ -15,7 +15,7 @@ def __init__(self, display, **kw): configpath = os.path.expanduser(os.environ.get("GLASS_GHOSTS_CONFIG", "~/.config/glass/components.yml")) with open(configpath) as f: - self.config = json.loads(json.dumps(yaml.load(f, Loader=yaml.SafeLoader)), object_hook=InfiniteGlass.fromjson(self.display)) + self.config = InfiniteGlass.load_yaml(f, self.display) self.components = {} self.components_by_pid = {} diff --git a/glass-config-init/glass_config_init/ghosts.yml b/glass-config-init/glass_config_init/ghosts.yml index 62d108a..e168d7c 100644 --- a/glass-config-init/glass_config_init/ghosts.yml +++ b/glass-config-init/glass_config_init/ghosts.yml @@ -9,7 +9,7 @@ ignore: - ["_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_MENU"] - ["_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_UTILITY"] - ["_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_SPLASH"] - - ["WM_WINDOW_ROLE", {"__jsonclass__": ["string", "GtkFileChooserDialog"]}] + - ["WM_WINDOW_ROLE", !string "GtkFileChooserDialog"] # Use these properties to match a window to an existing ghost match: @@ -68,17 +68,20 @@ ghost_update: # might match the same template (by design). templates: .*-gimp-gimp-.*: - WM_COMMAND: [{"__jsonclass__": ["string", "gimp"]}] + WM_COMMAND: !string gimp .*-gimp-2-8-.*: - WM_COMMAND: [{"__jsonclass__": ["string", "gimp-2.8"]}] + WM_COMMAND: !string gimp-2.8 # Predefine ghosts. Useful for configuring windows created by the # applications started as components. ghosts: - - IG_APP_ID: {"__jsonclass__": ["string", "panelterm"]} - WM_CLASS: [{"__jsonclass__": ["string", "xterm"]}, {"__jsonclass__": ["string", "XTerm"]}, {"__jsonclass__": ["string", ""]}] - WM_NAME: {"__jsonclass__": ["string", "panelterm"]} + - IG_APP_ID: !string panelterm + WM_CLASS: + - !string xterm + - !string XTerm + - !string "" + WM_NAME: !string panelterm IG_COORDS: [0.0, "eq://apply($.root.get_geometry).height/apply($.root.get_geometry).width", 1.0, 0.0576171875] IG_SIZE: ["eq://apply($.root.get_geometry).width", "eq://int(apply($.root.get_geometry).width*0.0576171875)"] IG_LAYER: IG_LAYER_OVERLAY diff --git a/glass-config-init/glass_config_init/widgets.yml b/glass-config-init/glass_config_init/widgets.yml index 36b63ef..b4f9e97 100644 --- a/glass-config-init/glass_config_init/widgets.yml +++ b/glass-config-init/glass_config_init/widgets.yml @@ -3,63 +3,49 @@ widgets: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.2 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/circle-plus.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/circle-plus.fl.svg action: zoom_to_fewer_windows Zoom out: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.3 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/circle-minus.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/circle-minus.fl.svg action: zoom_to_more_windows Zoom home: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.4 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/home.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/home.fl.svg action: zoom_home Group: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.5 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/group.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/group.fl.svg action: send_island_create Tile: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.6 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/th-list.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/th-list.fl.svg action: tile_visible_to_1_1 Exit: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.7 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/eject.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/eject.fl.svg action: send_exit Debug: properties: IG_COLOR_TRANSFORM: 1 IG_COORDS: [0.01, "eq://0.8 * apply($.root.get_geometry).height/apply($.root.get_geometry).width", 0.05, 0.05] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/bug.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/bug.fl.svg action: send_debug window-decorations: @@ -70,12 +56,8 @@ window-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.02, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/pause.fl.svg - IG_CONTENT_ALT: - type: IG_SVG - value: resource://glass_widgets/icons/play.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/pause.fl.svg + IG_CONTENT_ALT: !IG_SVG resource://glass_widgets/icons/play.fl.svg action: toggle_sleep Enable/disable ghosts: @@ -85,12 +67,8 @@ window-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.055, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/pin-inactive.fl.svg - IG_CONTENT_ALT: - type: IG_SVG - value: resource://glass_widgets/icons/pin-active.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/pin-inactive.fl.svg + IG_CONTENT_ALT: !IG_SVG resource://glass_widgets/icons/pin-active.fl.svg action: toggle_ghosts_enabled Close: @@ -99,9 +77,7 @@ window-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.09, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/times.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/times.fl.svg action: send_close Maximize: @@ -110,9 +86,7 @@ window-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.125, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/tv.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/tv.fl.svg action: zoom_1_1_1 #More: @@ -120,9 +94,7 @@ window-decorations: # IG_COORDS: [1.0, -1.0, 0.0, 0.0, # 0.01, 0.12, 0.02, 0.02] # IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - # IG_CONTENT: - # type: IG_SVG - # value: resource://glass_widgets/icons/bars.svg + # IG_CONTENT: !IG_SVG resource://glass_widgets/icons/bars.svg # action: "" island-decorations: @@ -132,12 +104,8 @@ island-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.02, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/pause.fl.svg - IG_CONTENT_ALT: - type: IG_SVG - value: resource://glass_widgets/icons/play.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/pause.fl.svg + IG_CONTENT_ALT: !IG_SVG resource://glass_widgets/icons/play.fl.svg action: island_toggle_sleep Close island: @@ -145,9 +113,7 @@ island-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.055, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/times.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/times.fl.svg action: island_delete Break apart island: @@ -155,9 +121,7 @@ island-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.09, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/unlink.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/unlink.fl.svg action: island_ungroup Change background: @@ -165,7 +129,5 @@ island-decorations: IG_COORDS: [1.0, -1.0, 0.0, 0.0, 0.01, 0.125, 0.03, 0.03] IG_COORD_TYPES: ["IG_COORD_PARENT_BASE", "IG_COORD_SCREEN_X"] - IG_CONTENT: - type: IG_SVG - value: resource://glass_widgets/icons/image.fl.svg + IG_CONTENT: !IG_SVG resource://glass_widgets/icons/image.fl.svg action: "island_change_background" diff --git a/glass-ghosts/glass_ghosts/manager.py b/glass-ghosts/glass_ghosts/manager.py index bffeadd..7a9a880 100644 --- a/glass-ghosts/glass_ghosts/manager.py +++ b/glass-ghosts/glass_ghosts/manager.py @@ -19,7 +19,7 @@ def __init__(self, display, **kw): configpath = os.path.expanduser(os.environ.get("GLASS_GHOSTS_CONFIG", "~/.config/glass/ghosts.yml")) with open(configpath) as f: - self.config = json.loads(json.dumps(yaml.load(f, Loader=yaml.SafeLoader)), object_hook=InfiniteGlass.fromjson(self.display)) + self.config = InfiniteGlass.load_yaml(f, self.display) self.changes = False self.windows = {} diff --git a/glass-islands/glass_islands/manager.py b/glass-islands/glass_islands/manager.py index 756954a..e0256f8 100644 --- a/glass-islands/glass_islands/manager.py +++ b/glass-islands/glass_islands/manager.py @@ -16,7 +16,7 @@ def __init__(self, display): configpath = os.path.expanduser(os.environ.get("GLASS_ISLANDS_CONFIG", "~/.config/glass/islands.yml")) with open(configpath) as f: - self.config = json.loads(json.dumps(yaml.load(f, Loader=yaml.SafeLoader)), object_hook=InfiniteGlass.fromjson(self.display)) + self.config = InfiniteGlass.load_yaml(f, self.display) self.changes = False self.islands = {} diff --git a/glass-lib/InfiniteGlass/valueencoding.py b/glass-lib/InfiniteGlass/valueencoding.py index 7ca2fde..e448197 100644 --- a/glass-lib/InfiniteGlass/valueencoding.py +++ b/glass-lib/InfiniteGlass/valueencoding.py @@ -6,6 +6,8 @@ import json from . import keymap import sakstig +import yaml +import base64 class apply(sakstig.Function): def call(self, global_qs, local_qs, args): @@ -196,3 +198,34 @@ def fromjson(obj): return tuple(cls[1:]) return obj return fromjson + +class YamlLoader(yaml.SafeLoader): + pass + +def _yaml_constructor(loader, tag_suffix, node): + if isinstance(node, yaml.nodes.ScalarNode): + value = loader.construct_scalar(node) + elif isinstance(node, yaml.nodes.MappingNode): + value = loader.construct_mapping(node) + elif isinstance(node, yaml.nodes.SequenceNode): + value = loader.construct_sequence(node) + else: + assert False, "Unknown node type: %s" % node + if tag_suffix.startswith("!array_"): + return array.array(tag_suffix[len("!array_"):], value) + elif tag_suffix == "!string": + return value.encode("utf-8") + elif tag_suffix == "!base64": + return base64.b64decode(value) + elif tag_suffix == "!WINDOW": + return loader.display.create_resource_object("window", value) + elif tag_suffix == "!tuple": + return tuple(value) + return {"type": tag_suffix[1:], "value": value} +YamlLoader.add_multi_constructor("", _yaml_constructor) + +def load_yaml(f, display=None): + d = display + class Loader(YamlLoader): + display = d + return yaml.load(f, Loader=Loader) diff --git a/glass-widgets/glass_widgets/__init__.py b/glass-widgets/glass_widgets/__init__.py index 18ddb1e..14f3a79 100644 --- a/glass-widgets/glass_widgets/__init__.py +++ b/glass-widgets/glass_widgets/__init__.py @@ -23,11 +23,11 @@ def redraw(display, win): @InfiniteGlass.profilable def main(*arg, **kw): - configpath = os.path.expanduser(os.environ.get("GLASS_WIDGET_CONFIG", "~/.config/glass/widgets.yml")) - with open(configpath) as f: - config = yaml.load(f, Loader=yaml.SafeLoader) - with InfiniteGlass.Display() as display: + configpath = os.path.expanduser(os.environ.get("GLASS_WIDGET_CONFIG", "~/.config/glass/widgets.yml")) + with open(configpath) as f: + config = InfiniteGlass.load_yaml(f, display) + for widget_type, widgets in config.items(): for name, widget in widgets.items(): w = display.root.create_window()