m3wal 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
m3wal/__init__.py ADDED
File without changes
m3wal/m3wal.py ADDED
@@ -0,0 +1,615 @@
1
+ """
2
+ M3WAL: Wallpaper to Material 3 Color Scheme Generator
3
+ Version: Official Library (material-color-utilities)
4
+
5
+ Install: pip install material-color-utilities Pillow
6
+ """
7
+
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ from material_color_utilities import Variant, hex_from_argb, theme_from_image
13
+ from PIL import Image
14
+
15
+
16
+ class M3WAL:
17
+ def __init__(self, wallpaper_path, config=None):
18
+ self.wallpaper_path = wallpaper_path
19
+ self.theme = None
20
+ self.mode = None
21
+ self.source_color = None
22
+ self.config = config if config else self.load_config()
23
+ self.brightness_threshold = int(self.config.get('General', 'brightness_threshold', fallback='128'))
24
+
25
+ def load_config(self):
26
+ """Load configuration from m3-colors.conf"""
27
+ import configparser
28
+
29
+ config_file = Path.home() / ".config" / "m3-colors" / "m3-colors.conf"
30
+
31
+ # Default config
32
+ defaults = {
33
+ 'mode': 'auto',
34
+ 'variant': 'CONTENT',
35
+ 'brightness_threshold': '128',
36
+ 'templates_dir': 'templates',
37
+ 'cache_dir': '~/.cache/m3-colors',
38
+ 'config_dir': '~/.config/m3-colors',
39
+ 'set_wallpaper': 'true',
40
+ 'apply_xresources': 'true',
41
+ 'generate_palette_preview': 'true',
42
+ 'run_post_script': 'true',
43
+ 'create_symlink': 'true',
44
+ 'script_path': 'm3wal-post.sh'
45
+ }
46
+
47
+ config = configparser.ConfigParser()
48
+
49
+ if config_file.exists():
50
+ config.read(config_file)
51
+ else:
52
+ # make default config
53
+ config['General'] = {
54
+ 'mode': defaults['mode'],
55
+ 'variant': defaults['variant'],
56
+ 'brightness_threshold': defaults['brightness_threshold']
57
+ }
58
+ config['Paths'] = {
59
+ 'templates_dir': defaults['templates_dir'],
60
+ 'cache_dir': defaults['cache_dir'],
61
+ 'config_dir': defaults['config_dir']
62
+ }
63
+ config['Features'] = {
64
+ 'set_wallpaper': defaults['set_wallpaper'],
65
+ 'apply_xresources': defaults['apply_xresources'],
66
+ 'generate_palette_preview': defaults['generate_palette_preview'],
67
+ 'run_post_script': defaults['run_post_script'],
68
+ 'create_symlink': defaults['create_symlink']
69
+ }
70
+ config['PostScript'] = {
71
+ 'script_path': defaults['script_path']
72
+ }
73
+
74
+ config_file.parent.mkdir(parents=True, exist_ok=True)
75
+ with open(config_file, 'w') as f:
76
+ config.write(f)
77
+
78
+ return config
79
+
80
+ def analyze_wallpaper(self):
81
+ """Extract dominant color & detect brightness"""
82
+ img = Image.open(self.wallpaper_path)
83
+
84
+ # Detect brightness for auto mode
85
+ grayscale = img.convert("L")
86
+ pixels = grayscale.tobytes()
87
+ avg_brightness = sum(pixels) / len(pixels)
88
+
89
+ # Auto select light/dark mode based on threshold
90
+ self.mode = "dark" if avg_brightness < self.brightness_threshold else "light"
91
+
92
+ return {"brightness": avg_brightness, "mode": self.mode}
93
+
94
+ def generate_scheme(self, mode=None, variant="CONTENT"):
95
+ """Generate Material 3 color scheme"""
96
+ if mode:
97
+ self.mode = mode
98
+
99
+ self.variant = variant
100
+
101
+ # Map string to Variant enum
102
+ variant_map = {
103
+ "TONALSPOT": Variant.TONALSPOT,
104
+ "VIBRANT": Variant.VIBRANT,
105
+ "EXPRESSIVE": Variant.EXPRESSIVE,
106
+ "NEUTRAL": Variant.NEUTRAL,
107
+ "FIDELITY": Variant.FIDELITY,
108
+ "CONTENT": Variant.CONTENT,
109
+ "MONOCHROME": Variant.MONOCHROME,
110
+ }
111
+
112
+ variant_enum = variant_map.get(variant.upper(), Variant.CONTENT)
113
+
114
+ # Generate theme from image
115
+ img = Image.open(self.wallpaper_path)
116
+ self.theme = theme_from_image(img, 0, variant_enum)
117
+
118
+ # Get source color
119
+ self.source_color = self.theme.source
120
+
121
+ return self._extract_colors()
122
+
123
+ def _extract_colors(self):
124
+ """Extract all M3 colors + 16 terminal colors"""
125
+ if not self.theme:
126
+ raise ValueError("Generate scheme first!")
127
+
128
+ # Select scheme based on mode
129
+ scheme = (
130
+ self.theme.schemes.dark if self.mode == "dark" else self.theme.schemes.light
131
+ )
132
+
133
+ m3_colors = {
134
+ # Primary
135
+ "m3primary": scheme.primary,
136
+ "m3onPrimary": scheme.on_primary,
137
+ "m3primaryContainer": scheme.primary_container,
138
+ "m3onPrimaryContainer": scheme.on_primary_container,
139
+ "m3primaryFixed": scheme.primary_fixed,
140
+ "m3primaryFixedDim": scheme.primary_fixed_dim,
141
+ "m3onPrimaryFixed": scheme.on_primary_fixed,
142
+ "m3onPrimaryFixedVariant": scheme.on_primary_fixed_variant,
143
+ # Secondary
144
+ "m3secondary": scheme.secondary,
145
+ "m3onSecondary": scheme.on_secondary,
146
+ "m3secondaryContainer": scheme.secondary_container,
147
+ "m3onSecondaryContainer": scheme.on_secondary_container,
148
+ "m3secondaryFixed": scheme.secondary_fixed,
149
+ "m3secondaryFixedDim": scheme.secondary_fixed_dim,
150
+ "m3onSecondaryFixed": scheme.on_secondary_fixed,
151
+ "m3onSecondaryFixedVariant": scheme.on_secondary_fixed_variant,
152
+ # Tertiary
153
+ "m3tertiary": scheme.tertiary,
154
+ "m3onTertiary": scheme.on_tertiary,
155
+ "m3tertiaryContainer": scheme.tertiary_container,
156
+ "m3onTertiaryContainer": scheme.on_tertiary_container,
157
+ "m3tertiaryFixed": scheme.tertiary_fixed,
158
+ "m3tertiaryFixedDim": scheme.tertiary_fixed_dim,
159
+ "m3onTertiaryFixed": scheme.on_tertiary_fixed,
160
+ "m3onTertiaryFixedVariant": scheme.on_tertiary_fixed_variant,
161
+ # Error
162
+ "m3error": scheme.error,
163
+ "m3onError": scheme.on_error,
164
+ "m3errorContainer": scheme.error_container,
165
+ "m3onErrorContainer": scheme.on_error_container,
166
+ # Surface
167
+ "m3surface": scheme.surface,
168
+ "m3onSurface": scheme.on_surface,
169
+ "m3surfaceVariant": scheme.surface_variant,
170
+ "m3onSurfaceVariant": scheme.on_surface_variant,
171
+ "m3surfaceDim": scheme.surface_dim,
172
+ "m3surfaceBright": scheme.surface_bright,
173
+ "m3surfaceContainerLowest": scheme.surface_container_lowest,
174
+ "m3surfaceContainerLow": scheme.surface_container_low,
175
+ "m3surfaceContainer": scheme.surface_container,
176
+ "m3surfaceContainerHigh": scheme.surface_container_high,
177
+ "m3surfaceContainerHighest": scheme.surface_container_highest,
178
+ # Background (deprecated in M3 but kept for compatibility)
179
+ "m3background": scheme.surface,
180
+ "m3onBackground": scheme.on_surface,
181
+ # Outline
182
+ "m3outline": scheme.outline,
183
+ "m3outlineVariant": scheme.outline_variant,
184
+ # Inverse
185
+ "m3inverseSurface": scheme.inverse_surface,
186
+ "m3inverseOnSurface": scheme.inverse_on_surface,
187
+ "m3inversePrimary": scheme.inverse_primary,
188
+ # Shadow & Scrim
189
+ "m3shadow": scheme.shadow,
190
+ "m3scrim": scheme.scrim,
191
+ }
192
+
193
+ # Generate terminal colors
194
+ terminal_colors = self._generate_terminal_colors(scheme)
195
+
196
+ return {**m3_colors, **terminal_colors}
197
+
198
+ def _generate_terminal_colors(self, scheme):
199
+ """Generate 16 terminal colors from M3 palette"""
200
+ return {
201
+ # Normal colors
202
+ "term0": scheme.surface_dim, # Black
203
+ "term1": scheme.error, # Red
204
+ "term2": scheme.tertiary, # Green
205
+ "term3": scheme.primary_fixed_dim, # Yellow
206
+ "term4": scheme.primary, # Blue
207
+ "term5": scheme.secondary, # Magenta
208
+ "term6": scheme.tertiary_container, # Cyan
209
+ "term7": scheme.on_surface, # White
210
+ # Bright colors
211
+ "term8": scheme.surface_container_high, # Bright Black
212
+ "term9": scheme.error_container, # Bright Red
213
+ "term10": scheme.tertiary_fixed, # Bright Green
214
+ "term11": scheme.primary_fixed, # Bright Yellow
215
+ "term12": scheme.primary_container, # Bright Blue
216
+ "term13": scheme.secondary_container, # Bright Magenta
217
+ "term14": scheme.tertiary_fixed_dim, # Bright Cyan
218
+ "term15": scheme.surface_bright, # Bright White
219
+ }
220
+
221
+ def apply_all_templates(self, templates_dir=None, output_dir=None):
222
+ """Apply colors to all templates in templates directory"""
223
+ if not self.theme:
224
+ raise ValueError("Generate scheme first!")
225
+
226
+ if output_dir is None:
227
+ output_dir = Path.home() / ".cache" / "m3-colors"
228
+
229
+ # Use package templates if not specified
230
+ if templates_dir is None:
231
+ try:
232
+ import pkg_resources
233
+ templates_dir = pkg_resources.resource_filename('m3wal', 'templates')
234
+ except:
235
+ # Fallback to config dir
236
+ templates_dir = Path.home() / ".config" / "m3-colors" / "templates"
237
+
238
+ templates_path = Path(templates_dir)
239
+ output_path = Path(output_dir)
240
+ output_path.mkdir(parents=True, exist_ok=True)
241
+
242
+ # Cari semua file .template
243
+ template_files = list(templates_path.glob("*.template"))
244
+
245
+ if not template_files:
246
+ print(f"No template files found in {templates_dir}/")
247
+ return []
248
+
249
+ generated_files = []
250
+
251
+ print(f"\nApplying colors to templates...")
252
+ for template_file in template_files:
253
+ # Hilangkan ekstensi .template untuk nama output
254
+ output_filename = template_file.stem
255
+ output_file = output_path / output_filename
256
+
257
+ try:
258
+ self.apply_template(template_file, output_file)
259
+ generated_files.append(str(output_file))
260
+ print(f"✓ {template_file.name} → {output_file}")
261
+ except Exception as e:
262
+ print(f"✗ {template_file.name}: {e}")
263
+
264
+ return generated_files
265
+
266
+ def create_wallpaper_symlink(self):
267
+ """Create symlink to current wallpaper in ~/.config/m3-colors"""
268
+ config_dir = Path.home() / ".config" / "m3-colors"
269
+ config_dir.mkdir(parents=True, exist_ok=True)
270
+
271
+ symlink_path = config_dir / "current_wallpaper"
272
+ wallpaper_path = Path(self.wallpaper_path).resolve()
273
+
274
+ # Delete old symlink if exist
275
+ if symlink_path.exists() or symlink_path.is_symlink():
276
+ symlink_path.unlink()
277
+
278
+ # Make new symlink
279
+ symlink_path.symlink_to(wallpaper_path)
280
+ print(f"Created symlink → {symlink_path}")
281
+
282
+ def load_deploy_config(self):
283
+ """Load deployment mappings from config"""
284
+ config_file = Path.home() / ".config" / "m3-colors" / "deploy.json"
285
+
286
+ default_config = {
287
+ "deployments": [
288
+ {"source": "colors-nvim.lua", "destination": "~/.config/nvim/lua/themes/material3.lua"},
289
+ {"source": "gtkrc", "destination": "~/.local/share/themes/FlatColor/gtk-2.0/gtkrc"},
290
+ {"source": "gtk.css", "destination": "~/.local/share/themes/FlatColor/gtk-3.0/gtk.css"},
291
+ {"source": "gtk.3.20", "destination": "~/.local/share/themes/FlatColor/gtk-3.20/gtk.css"}
292
+ ]
293
+ }
294
+
295
+ if config_file.exists():
296
+ with open(config_file, 'r') as f:
297
+ return json.load(f)
298
+ else:
299
+ config_file.parent.mkdir(parents=True, exist_ok=True)
300
+ with open(config_file, 'w') as f:
301
+ json.dump(default_config, f, indent=2)
302
+ return default_config
303
+
304
+ def deploy_configs(self):
305
+ """Deploy configs based on deploy.json"""
306
+ import shutil
307
+
308
+ cache_dir = Path.home() / ".cache" / "m3-colors"
309
+ config = self.load_deploy_config()
310
+
311
+ for item in config.get("deployments", []):
312
+ src = cache_dir / item["source"]
313
+ dest = Path(item["destination"]).expanduser()
314
+
315
+ if src.exists():
316
+ dest.parent.mkdir(parents=True, exist_ok=True)
317
+ shutil.copy2(src, dest)
318
+ print(f"{item['source']} → {dest}")
319
+ else:
320
+ print(f"{item['source']} not found")
321
+
322
+ def run_post_script(self, script_path=None):
323
+ """Run post-generation script"""
324
+ import subprocess
325
+
326
+ if script_path is None:
327
+ script_path = Path.home() / ".config" / "m3-colors" / "m3wal-post.sh"
328
+
329
+ script = Path(script_path).expanduser()
330
+ if script.exists():
331
+ subprocess.run(["bash", str(script)])
332
+ print(f"Executed {script.name}")
333
+
334
+ def apply_xresources(self):
335
+ import subprocess
336
+
337
+ xresources = Path.home() / ".cache" / "m3-colors" / "colors.Xresources"
338
+ if xresources.exists():
339
+ subprocess.run(["xrdb", "-merge", str(xresources)])
340
+ print(f"Applied Xresources")
341
+
342
+ def export_json(self, output_path=None, variant="CONTENT"):
343
+ """Export scheme to JSON"""
344
+ if not self.theme:
345
+ raise ValueError("Generate scheme first!")
346
+ colors = self._extract_colors()
347
+
348
+ # Save to ~/.config/m3-colors/output only
349
+ config_dir = Path.home() / ".config" / "m3-colors" / "output"
350
+ config_dir.mkdir(parents=True, exist_ok=True)
351
+ wallpaper_name = Path(self.wallpaper_path).stem
352
+ config_path = config_dir / f"{wallpaper_name}_{variant}_scheme.json"
353
+
354
+ output = {
355
+ "wallpaper": self.wallpaper_path,
356
+ "mode": self.mode,
357
+ "variant": variant,
358
+ "source_color": (
359
+ hex_from_argb(self.source_color)
360
+ if isinstance(self.source_color, int)
361
+ else self.source_color
362
+ ),
363
+ "colors": colors,
364
+ }
365
+
366
+ with open(config_path, "w") as f:
367
+ json.dump(output, f, indent=2)
368
+
369
+ print(f"Exported to: {config_path}")
370
+ return str(config_path)
371
+
372
+ def set_wallpaper(self):
373
+ """Set wallpaper using feh"""
374
+ import subprocess
375
+
376
+ wallpaper = Path(self.wallpaper_path).expanduser()
377
+ if wallpaper.exists():
378
+ subprocess.run(["feh", "--bg-fill", str(wallpaper)])
379
+ print(f"Set wallpaper with feh")
380
+
381
+ def apply_template(self, template_path, output_path):
382
+ """Apply colors to template file"""
383
+ if not self.theme:
384
+ raise ValueError("Generate scheme first!")
385
+
386
+ colors = self._extract_colors()
387
+
388
+ # Add metadata to dictionary colors
389
+ colors["wallpaper_path"] = self.wallpaper_path
390
+ colors["mode"] = self.mode
391
+ colors["source_color"] = (
392
+ hex_from_argb(self.source_color)
393
+ if isinstance(self.source_color, int)
394
+ else self.source_color
395
+ )
396
+
397
+ with open(template_path, "r") as f:
398
+ template = f.read()
399
+
400
+ # Replace {{m3primary}}, {{term0}}, {{wallpaper_path}}, etc.
401
+ for key, value in colors.items():
402
+ template = template.replace(f"{{{{{key}}}}}", str(value))
403
+
404
+ with open(output_path, "w") as f:
405
+ f.write(template)
406
+
407
+ return output_path
408
+
409
+ def generate_palette_preview(self, output_path=None):
410
+ """Generate color palette preview image"""
411
+ if not self.theme:
412
+ raise ValueError("Generate scheme first!")
413
+ try:
414
+ from PIL import Image, ImageDraw, ImageFont
415
+ except ImportError:
416
+ print("PIL/Pillow not installed. Install: pip install Pillow")
417
+ return None
418
+
419
+ variant = self.variant if hasattr(self, 'variant') else 'CONTENT'
420
+ colors_dict = self._extract_colors()
421
+
422
+ # All sequence M3 color
423
+ all_colors = [
424
+ # Primary colors
425
+ 'm3primary', 'm3onPrimary', 'm3primaryContainer', 'm3onPrimaryContainer',
426
+ 'm3primaryFixed', 'm3primaryFixedDim', 'm3onPrimaryFixed', 'm3onPrimaryFixedVariant',
427
+
428
+ # Secondary colors
429
+ 'm3secondary', 'm3onSecondary', 'm3secondaryContainer', 'm3onSecondaryContainer',
430
+ 'm3secondaryFixed', 'm3secondaryFixedDim', 'm3onSecondaryFixed', 'm3onSecondaryFixedVariant',
431
+
432
+ # Tertiary colors
433
+ 'm3tertiary', 'm3onTertiary', 'm3tertiaryContainer', 'm3onTertiaryContainer',
434
+ 'm3tertiaryFixed', 'm3tertiaryFixedDim', 'm3onTertiaryFixed', 'm3onTertiaryFixedVariant',
435
+
436
+ # Error colors
437
+ 'm3error', 'm3onError', 'm3errorContainer', 'm3onErrorContainer',
438
+
439
+ # Surface colors
440
+ 'm3surface', 'm3onSurface', 'm3surfaceVariant', 'm3onSurfaceVariant',
441
+ 'm3surfaceDim', 'm3surfaceBright', 'm3surfaceContainerLowest', 'm3surfaceContainerLow',
442
+ 'm3surfaceContainer', 'm3surfaceContainerHigh', 'm3surfaceContainerHighest',
443
+
444
+ # Outline colors
445
+ 'm3outline', 'm3outlineVariant',
446
+
447
+ # Inverse colors
448
+ 'm3inverseSurface', 'm3inverseOnSurface', 'm3inversePrimary',
449
+
450
+ # Shadow & Scrim
451
+ 'm3shadow', 'm3scrim',
452
+ ]
453
+
454
+ # Terminal colors
455
+ all_colors.extend([f'term{i}' for i in range(16)])
456
+
457
+ # Filter
458
+ available_colors = [key for key in all_colors if colors_dict.get(key) is not None]
459
+
460
+ # configuration grid
461
+ MAX_COLS = 16
462
+ cell_width = 80
463
+ cell_height = 60
464
+
465
+ # count how many column/row that we need
466
+ total_colors = len(available_colors)
467
+ num_rows = (total_colors + MAX_COLS - 1) // MAX_COLS # Ceiling division
468
+
469
+ # make image
470
+ img_width = cell_width * MAX_COLS
471
+ img_height = cell_height * num_rows
472
+ img = Image.new('RGB', (img_width, img_height), 'white')
473
+ draw = ImageDraw.Draw(img)
474
+
475
+ # Draw every color
476
+ for idx, color_key in enumerate(available_colors):
477
+ color_value = colors_dict.get(color_key)
478
+ if color_value is None:
479
+ continue
480
+
481
+ # count grid position
482
+ col_idx = idx % MAX_COLS
483
+ row_idx = idx // MAX_COLS
484
+
485
+ # Convert ARGB to hex
486
+ if isinstance(color_value, int):
487
+ hex_color = hex_from_argb(color_value)
488
+ else:
489
+ hex_color = color_value
490
+
491
+ # Remove # if exists
492
+ color_clean = hex_color.replace('#', '')
493
+ # Convert hex to RGB
494
+ rgb = tuple(int(color_clean[j:j+2], 16) for j in (0, 2, 4))
495
+
496
+ # Position
497
+ x = col_idx * cell_width
498
+ y = row_idx * cell_height
499
+
500
+ # Draw rectangle
501
+ draw.rectangle([x, y, x + cell_width, y + cell_height], fill=rgb)
502
+
503
+ # Save
504
+ if output_path is None:
505
+ output_dir = Path.home() / ".config" / "m3-colors" / "sample"
506
+ output_dir.mkdir(parents=True, exist_ok=True)
507
+ wallpaper_name = Path(self.wallpaper_path).stem
508
+ output_path = output_dir / f"{wallpaper_name}_{variant}_palette.png"
509
+
510
+ img.save(output_path)
511
+ print(f"Palette preview saved: {output_path}")
512
+
513
+ return str(output_path)
514
+
515
+ def preview_colors(self):
516
+ """Print color preview"""
517
+ if not self.theme:
518
+ raise ValueError("Generate scheme first!")
519
+
520
+ colors = self._extract_colors()
521
+
522
+ print(f"\nColor Preview ({self.mode} mode):")
523
+ print(
524
+ f" Source: {hex_from_argb(self.source_color) if isinstance(self.source_color, int) else self.source_color}"
525
+ )
526
+ print(f"\n Primary: {colors['m3primary']}")
527
+ print(f" Secondary: {colors['m3secondary']}")
528
+ print(f" Tertiary: {colors['m3tertiary']}")
529
+ print(f" Surface: {colors['m3surface']}")
530
+ print(f" Error: {colors['m3error']}")
531
+
532
+ print(f"\n Terminal Colors:")
533
+ for i in range(16):
534
+ print(f" term{i}: {colors[f'term{i}']}")
535
+
536
+ def main():
537
+ if len(sys.argv) < 2:
538
+ print("Usage: python m3wal.py <wallpaper_path> [light|dark|auto] [variant]")
539
+ print("\nVariants: TONALSPOT, VIBRANT, EXPRESSIVE, NEUTRAL, FIDELITY, CONTENT, MONOCHROME")
540
+ print("Default: uses m3-colors.conf settings")
541
+ sys.exit(1)
542
+
543
+ wallpaper = sys.argv[1]
544
+
545
+ # Initialize and load config
546
+ m3wal = M3WAL(wallpaper)
547
+
548
+ # Override config with CLI args if provided
549
+ mode = sys.argv[2] if len(sys.argv) > 2 else m3wal.config.get('General', 'mode', fallback='auto')
550
+ variant = sys.argv[3] if len(sys.argv) > 3 else m3wal.config.get('General', 'variant', fallback='CONTENT')
551
+
552
+ # Analyze wallpaper
553
+ print("Analyzing wallpaper...")
554
+ analysis = m3wal.analyze_wallpaper()
555
+ print(f" Brightness: {analysis['brightness']:.1f} (threshold: {m3wal.brightness_threshold})")
556
+ print(f" Auto-detected mode: {analysis['mode']}")
557
+
558
+ # Generate scheme
559
+ if mode == "auto":
560
+ mode = analysis["mode"]
561
+
562
+ print(f"\nGenerating {mode} scheme with {variant} variant...")
563
+ colors = m3wal.generate_scheme(mode, variant)
564
+ print(f"Generated {len(colors)} colors")
565
+
566
+ # Export to JSON
567
+ output = m3wal.export_json(variant=variant)
568
+
569
+ # Apply to all templates
570
+ cache_dir = Path(m3wal.config.get('Paths', 'cache_dir', fallback='~/.cache/m3-colors')).expanduser()
571
+ generated_files = m3wal.apply_all_templates(output_dir=cache_dir)
572
+
573
+ if generated_files:
574
+ print(f"\nGenerated {len(generated_files)} config files")
575
+
576
+ # Deploy configs
577
+ print("\nDeploying configs...")
578
+ m3wal.deploy_configs()
579
+
580
+ # Apply Xresources
581
+ if m3wal.config.getboolean('Features', 'apply_xresources', fallback=True):
582
+ print("\nApplying Xresources...")
583
+ m3wal.apply_xresources()
584
+
585
+ # Set wallpaper
586
+ if m3wal.config.getboolean('Features', 'set_wallpaper', fallback=True):
587
+ print("\nSetting wallpaper...")
588
+ m3wal.set_wallpaper()
589
+
590
+ # Create wallpaper symlink
591
+ if m3wal.config.getboolean('Features', 'create_symlink', fallback=True):
592
+ print("\nCreating wallpaper symlink...")
593
+ m3wal.create_wallpaper_symlink()
594
+
595
+ # Run post script
596
+ if m3wal.config.getboolean('Features', 'run_post_script', fallback=True):
597
+ script_path = m3wal.config.get('PostScript', 'script_path', fallback='m3wal-post.sh')
598
+ # if relative path, merge with config_dir
599
+ if not Path(script_path).is_absolute():
600
+ config_dir = Path(m3wal.config.get('Paths', 'config_dir', fallback='~/.config/m3-colors')).expanduser()
601
+ script_path = config_dir / script_path
602
+
603
+ print("\nRunning post script...")
604
+ m3wal.run_post_script(script_path)
605
+
606
+ # Show preview
607
+ m3wal.preview_colors()
608
+
609
+ # Generate palette preview
610
+ if m3wal.config.getboolean('Features', 'generate_palette_preview', fallback=True):
611
+ print("\nGenerating palette preview...")
612
+ m3wal.generate_palette_preview()
613
+
614
+ if __name__ == "__main__":
615
+ main()
@@ -0,0 +1,5 @@
1
+ # Alacritty Config - Generated by WPG-M3
2
+
3
+ [colors.primary]
4
+ background = '{{m3surface}}'
5
+ foreground = '{{m3onSurface}}'