File Coverage

blib/lib/Tk/GtkSettings.pm
Criterion Covered Total %
statement 220 274 80.2
branch 79 164 48.1
condition 1 3 33.3
subroutine 31 40 77.5
pod 34 34 100.0
total 365 515 70.8


line stmt bran cond sub pod time code
1             package Tk::GtkSettings;
2              
3             =head1 NAME
4              
5             Tk::GtkSettings - Give Tk applications the looks of Gtk applications
6              
7             =cut
8              
9 1     1   72841 use strict;
  1         3  
  1         28  
10 1     1   7 use warnings;
  1         2  
  1         24  
11 1     1   5 use File::Basename;
  1         3  
  1         96  
12 1     1   7 use Config;
  1         2  
  1         39  
13             our $VERSION = '0.05';
14              
15 1     1   4 use Exporter;
  1         3  
  1         3731  
16             our @ISA = qw(Exporter);
17             our %EXPORT_TAGS = ( 'all' => [ qw(
18             $delete_output
19             $gtkpath
20             $verbose
21             $out_file
22             alterColor
23             appName
24             convertColorCode
25             export2file
26             export2Xdefaults
27             export2xrdb
28             export2Xresources
29             groupAdd
30             groupAll
31             groupDelete
32             groupExists
33             groupMembers
34             groupMembersAdd
35             groupMembersReplace
36             groupOption
37             groupOptionAll
38             groupOptionDelete
39             gtkKey
40             gtkKeyAll
41             gtkKeyDelete
42             hex2rgb
43             hexstring
44             initDefaults
45             loadGtkInfo
46             platformPermitted
47             removefromFile
48             removeFromXdefaults
49             removeFromXresources
50             removeFromxrdb
51             resetAll
52             rgb2hex
53             ) ] );
54             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} });
55              
56             our @EXPORT = qw(
57             applyGtkSettings
58             );
59              
60             sub appName;
61             sub export2xrdb;
62             sub generateOutput;
63             sub initDefaults;
64             sub loadGtkInfo;
65             sub platformPermitted;
66             sub resetAll;
67              
68             our $delete_output = 1;
69             our $gtkpath;
70             our $verbose = 0;
71             our $out_file;
72              
73             if (platformPermitted) {
74             $gtkpath = $ENV{HOME} . "/.config/gtk-3.0/";
75             $out_file = $ENV{HOME} . "/.tkgtksettings";
76             }
77              
78             my $no_gtk = 0;
79             my %gtksettings = ();
80             my %groups = (main => [[''], {}]);
81             my $app_name = basename($0);
82             my $marker;
83              
84             my @basegtkeys = qw(
85             theme_fg_color
86             theme_bg_color
87             theme_text_color
88             theme_base_color
89             theme_view_hover_decoration_color
90             theme_hovering_selected_bg_color
91             theme_selected_bg_color
92             theme_selected_fg_color
93             theme_view_active_decoration_color
94             theme_button_background_normal
95             theme_button_decoration_hover
96             theme_button_decoration_focus
97             theme_button_foreground_normal
98             theme_button_foreground_active
99             borders
100             warning_color
101             success_color
102             error_color
103             theme_unfocused_fg_color
104             theme_unfocused_text_color
105             theme_unfocused_bg_color
106             theme_unfocused_base_color
107             theme_unfocused_selected_bg_color_alt
108             theme_unfocused_selected_bg_color
109             theme_unfocused_selected_fg_color
110             theme_button_background_backdrop
111             theme_button_decoration_hover_backdrop
112             theme_button_decoration_focus_backdrop
113             theme_button_foreground_backdrop
114             theme_button_foreground_active_backdrop
115             unfocused_borders
116             warning_color_backdrop
117             success_color_backdrop
118             error_color_backdrop
119             insensitive_fg_color
120             insensitive_base_fg_color
121             insensitive_bg_color
122             insensitive_base_color
123             insensitive_selected_bg_color
124             insensitive_selected_fg_color
125             theme_button_background_insensitive
126             theme_button_decoration_hover_insensitive
127             theme_button_decoration_focus_insensitive
128             theme_button_foreground_insensitive
129             theme_button_foreground_active_insensitive
130             insensitive_borders
131             warning_color_insensitive
132             success_color_insensitive
133             error_color_insensitive
134             insensitive_unfocused_fg_color
135             theme_unfocused_view_text_color
136             insensitive_unfocused_bg_color
137             theme_unfocused_view_bg_color
138             insensitive_unfocused_selected_bg_color
139             insensitive_unfocused_selected_fg_color
140             theme_button_background_backdrop_insensitive
141             theme_button_decoration_hover_backdrop_insensitive
142             theme_button_decoration_focus_backdrop_insensitive
143             theme_button_foreground_backdrop_insensitive
144             theme_button_foreground_active_backdrop_insensitive
145             unfocused_insensitive_borders
146             warning_color_insensitive_backdrop
147             success_color_insensitive_backdrop
148             error_color_insensitive_backdrop
149             link_color
150             link_visited_color
151             tooltip_text
152             tooltip_background
153             tooltip_border
154             content_view_bg
155             );
156              
157             my @contentwidgets = qw(
158             Entry
159             FloatEntry
160             PodText
161             Spinbox
162             Text
163             TextUndo
164             TextEditor
165             ROText
166             XText
167             );
168              
169             my @listwidgets = qw(
170             Dirlist
171             DirTree
172             HList
173             ITree
174             IconList
175             Listbox
176             Tlist
177             Tree
178             );
179              
180             my %mainoptions = qw(
181             background theme_bg_color
182             foreground theme_fg_color
183             font gtk-font-name
184             activeBackground tk-active-background
185             activeForeground theme_fg_color
186             backPageColor tk-through-color
187             highlightBackground theme_bg_color
188             highlightColor theme_hovering_selected_bg_color
189             inactiveBackground tk-through-color
190             insertBackground theme_fg_color
191             selectBackground theme_selected_bg_color
192             selectForeground theme_selected_fg_color
193             troughColor tk-through-color
194             );
195              
196             my %contentoptions = qw(
197             background content_view_bg
198             highlightColor theme_bg_color
199             );
200              
201             my %listoptions = qw(
202             background content_view_bg
203             highlightColor theme_bg_color
204             );
205              
206             appName(basename($0));
207              
208             =head1 SYNOPSIS
209              
210             =over 4
211              
212             use Tk::GtkSettings;
213             applyGtkSettings;
214            
215             #or
216            
217             use Tk::GtkSettings qw(initDefaults export2xrdb);
218             initDefaults;
219             #do your adjustments here
220             export2xrdb;
221            
222             #then initialize your perl/Tk app.
223            
224             use Tk;
225             my $w = new MainWindow;
226            
227             #Do your stuff here
228            
229             $w->MainLoop;
230              
231             =back
232              
233             =head1 ABSTRACT
234              
235             Apply Gtk colors and fonts to your perl/Tk application
236              
237             =head1 DESCRIPTION
238              
239             Tk::GtkSettings attempts to overcome some very old complaints about Tk:
240              
241             - It's ugly!
242             - It's complicated to adjust colors and fonts to your desktop style
243              
244             Tk::GtkSettings loads your Gtk configuration files and applies it's font and color settings to your perl/Tk application.
245              
246             B loads some nice (at least we think so) default settings that copies your Gtk theme pretty well.
247              
248             However, it gives plenty of tools for you to adjust it and mess it up any way you like.
249              
250             It is harmless to install on Windows or Mac. It just will not do anything on these systems. That makes it
251             smooth to add as a dependency to your own package if you want it to be able to run on Windows and Mac as well.
252              
253             In working with colors it assumes 8-bit color depth.
254              
255             =head1 EXPORTS
256              
257             =over 4
258              
259             =item B<$delete_output>
260              
261             =over 4
262              
263             Usefull for testing and debugging. B exports to a file which then is sent to xrdb.
264             It checks if this file should be deleted when done. Default value is 1.
265              
266             =back
267              
268             =item B<$gtkpath>
269              
270             =over 4
271              
272             Usefull for testing. Default value is ~/.config/gtk-3.0/. That is the location where the
273             Gtk configuration files reside. This variable is not defined when on Windows or Mac.
274              
275             =back
276              
277             =item B<$out_file>
278              
279             =over 4
280              
281             Default value ~/.tkgtksettings. Used by B. This variable is not defined
282             on Windows or Mac.
283              
284             =back
285              
286             =item B<$verbose>
287              
288             =over 4
289              
290             Usefull for testing and debugging. Default value is 0. If set B will
291             complain about everything not in order. Otherwise it will quietly fail.
292              
293             =back
294              
295             =item B(I<$hexcolor>, I<$offset>)
296              
297             =over 4
298              
299             Adjusts $hexcolor by $offset. It takes every color chanel and adds or substracts $offset.
300             If the channel value is greater than 127 it will substract, otherwise it will add.
301              
302             alterColor('#000000', 1) returns #010101
303             alterColor('#FFFFFF', 1) returns #FEFEFE
304              
305             =back
306              
307             =cut
308              
309             sub alterColor {
310 5     5 1 21 my ($hex, $offset) = @_;
311 5         10 my @rgb = hex2rgb($hex);
312 5         10 my @rgba = ();
313 5         11 for (@rgb) {
314 15 100       24 if ($_ < 128) {
315 3         5 my $c = $_ + $offset;
316 3 50       7 $c = 0 if $c < 0;
317 3         5 push @rgba, $c
318             } else {
319 12         17 my $c = $_ - $offset;
320 12 50       23 $c = 255 if $c > 255;
321 12         23 push @rgba, $c
322             }
323             }
324 5         11 return rgb2hex(@rgba)
325             }
326              
327             =item B
328              
329             =over 4
330              
331             Just making life easy. Call this one and your done, unless you require adjustments.
332             It calls B and exports the whole bunch to xrdb.
333             Exported by default.
334              
335             =back
336              
337             =cut
338              
339             sub applyGtkSettings {
340 0 0   0 1 0 return unless platformPermitted;
341 0         0 initDefaults;
342 0         0 export2xrdb;
343             }
344              
345             =item B(I<$name>)
346              
347             =over 4
348              
349             Sets and returns your application name. By default it is set to the basename of what is in B<$0>. Your Gtk settings
350             will only be applied to your application in xrdb. You can set it to an empty string. Then it will
351             apply your Gtk settings to all your perl/Tk applications.
352              
353             =back
354              
355             =cut
356              
357             sub appName {
358 1 50   1 1 3 if (@_ ) {
359 1         3 $app_name = shift;
360 1         3 $marker = "!$app_name Tk::GtkSettings section\n";
361             }
362 1         2 return $app_name
363             }
364              
365             =item B(I<'rgb(255, 0, 0)'>)
366              
367             =over 4
368              
369             Some color settings in the Gtk configuration files are in the format 'rgb(255, 255, 255)'.
370             B converts these to a hex color string.
371              
372             =back
373              
374             =cut
375              
376             sub convertColorCode {
377 1     1 1 553 my $input = shift;
378 1 50       11 if ($input =~ /rgb\((\d+),(\d+),(\d+)\)/) {
379 1         8 my $r = substr(sprintf("0x%X", $1), 2);
380 1         5 my $g = substr(sprintf("0x%X", $2), 2);
381 1         5 my $b = substr(sprintf("0x%X", $3), 2);
382 1         4 return "#$r$g$b"
383             }
384             }
385              
386             =item B)
387              
388             =over 4
389              
390             Converts the font string in gtk to something Tk can handle
391              
392             =back
393              
394             =cut
395              
396             # {Khmer OS Battambang} -12 bold italic
397             sub decodeFont {
398 2     2 1 6 my $rawfont = shift;
399 2         6 my $family = '';
400 2         4 my $style = '';
401 2         4 my $size = '';
402 2 50       16 if ($rawfont =~ s/^([^,]+),//) {
403 2         5 $family = $1;
404             }
405 2         8 $rawfont =~ s/^\s*//; #remove leading spaces
406 2 50       11 if ($rawfont =~ s/^([^\d]+)//) {
407 0         0 $style = $1;
408 0         0 $style =~ s/^\s*//; #remove leading spaces
409 0         0 $style =~ s/\s*!//; #remove trailing spaces
410 0         0 $style = lc($style);
411             }
412 2 50       11 if ($rawfont =~ s/^(\d+)//) {
413 2         5 $size = $1;
414 2         6 $size =~ s/\s*!//; #remove trailing spaces
415             }
416 2         10 return "{$family} $size $style"
417             }
418              
419             =item B(I<$file>, ?I<$removeflag>?)
420              
421             =over 4
422              
423             Exports your Gtk settings to $file in a format recognized by xrdb. It looks for a section
424             in the file marked by appName . "Tk::GtkSettings section\n". If it finds it it will replace this section.
425             Otherwise it will append your Gtk settings to the end of the file. If $file does not yet exist it
426             will create it. if $removeflag is true it will not export but remove the section from $file.
427              
428             =back
429              
430             =cut
431              
432             sub export2file {
433 2     2 1 7 my ($file, $remove) = @_;
434 2 100       57 $remove = 0 unless defined $remove;
435 2         5 my $out = "";
436 2         4 my $found = 0;
437 2 50       32 if (-e $file) {
438 2 50       63 unless (open(XDEF, "<$file")) {
439 0 0       0 warn "cannot open $file" if $verbose;
440             return
441 0         0 }
442 2         10 my $inside = 0;
443 2         62 while (my $l = ) {
444 64 100       123 if ($inside) {
445 49 100       107 if ($l eq $marker) {
446 1         4 $inside = 0;
447             }
448             } else {
449 15 100       26 if ($l eq $marker) {
450 1         2 $inside = 1;
451 1         3 $found = 1;
452 1 50       4 $out = "$out$l" . generateOutput . $l unless $remove;
453             } else {
454 14         48 $out = "$out$l";
455             }
456             }
457             }
458 2         20 close XDEF;
459             }
460 2 100       8 unless ($found) {
461 1         9 $out = "$out\n$marker" . generateOutput . "$marker\n"
462             }
463 2 50       144 unless (open(XDEFO, ">$file")) {
464 0 0       0 warn "cannot open $file" if $verbose;
465             return
466 0         0 }
467 2         33 print XDEFO $out;
468 2         204 close XDEFO;
469             }
470              
471             =item B(?I<$removeflag>?)
472              
473             =over 4
474              
475             Same as B, however the file is always '~/.Xdefaults'.
476              
477             =back
478              
479             =cut
480              
481             sub export2Xdefaults {
482 0     0 1 0 export2file('~/.Xdefaults');
483             }
484              
485             =item B(?I<$removeflag>?)
486              
487             =over 4
488              
489             Same as B, however the file is always '~/.Xresources'.
490              
491             =back
492              
493             =cut
494              
495             sub export2Xresources {
496 0     0 1 0 export2file('~/.Xresources');
497             }
498              
499             =item B
500              
501             =over 4
502              
503             exports your Gtk settings directly to the xrdb database.
504              
505             =back
506              
507             =cut
508              
509             sub export2xrdb {
510 0 0   0 1 0 return unless platformPermitted;
511 0 0       0 return if $no_gtk;
512 0 0       0 if (open(OFILE, ">", $out_file)) {
513 0         0 print OFILE generateOutput;
514 0         0 close OFILE;
515 0         0 system "xrdb $out_file";
516 0 0       0 unlink $out_file if $delete_output;
517             }
518             }
519              
520             =item B
521              
522             =over 4
523              
524             Generates the output used by the export functions. Returns a string.
525              
526             =back
527              
528             =cut
529              
530             sub generateOutput {
531 1 50   1 1 3 return if $no_gtk;
532 1 50       4 return unless platformPermitted;
533 1         5 my $output = '';
534             #group main has to be done first.
535 1         8 my (@g) = ('main');
536 1         7 for (sort keys %groups) {
537 4 100       11 push @g, $_ unless $_ eq 'main';
538             }
539 1         4 for (@g) {
540 4         6 my $name = $_;
541 4         7 my $group = $groups{$name};
542 4         6 my $options = $group->[1];
543 4         5 my $mem = $group->[0];
544 4         5 for (@$mem) {
545 12         18 my $member = $_;
546 12         33 for (sort keys %$options) {
547 34         57 my $val = gtkKey($options->{$_});
548 34 100       57 $val = $options->{$_} unless defined $val;
549 34 100       52 unless ($name eq 'main') {
550 21         73 $output = $output . $app_name . "*$member." . $_ . ": " . $val . "\n";
551             } else {
552 13         37 $output = $output . $app_name . '*' . $_ . ": " . $val . "\n";
553             }
554             }
555             }
556             }
557 1         16 return $output
558             }
559              
560             =item B(I<$groupname>, I<\@members>, I<\%options>)
561              
562             =over 4
563              
564             Adds $groupname to the groups hash. If @members or %options are not specified,
565             it will leave them empty.
566              
567             =back
568              
569             =cut
570              
571             sub groupAdd {
572 7     7 1 271 my ($group, $members, $options) = @_;
573 7 50       17 unless (defined $group) {
574 0 0       0 warn "group is not defined" if $verbose;
575             return
576 0         0 }
577 7 50       12 $members = [] unless defined $members;
578 7 50       15 $options = {} unless defined $options;
579 7 50       13 unless (exists $groups{$group}) {
580 7         30 $groups{$group} = [$members, $options]
581             } else {
582 0 0       0 warn "group $group already exists" if $verbose
583             }
584             }
585              
586             =item B
587              
588             =over 4
589              
590             Returns a list of all available groups.
591              
592             =back
593              
594             =cut
595              
596             sub groupAll {
597 1     1 1 8 return keys %groups
598             }
599              
600             =item B(I<$groupname>)
601              
602             =over 4
603              
604             Removes $groupsname from the groups hash. You cannot delete the 'main' group.
605              
606             =back
607              
608             =cut
609              
610             sub groupDelete {
611 2     2 1 6 my $group = shift;
612 2 50       5 if (groupExists($group)) {
613 2 100       6 if ($group eq 'main') {
614 1 50       4 warn "deleting main group is not allowed" if $verbose;
615 1         3 return 0
616             }
617 1         3 delete $groups{$group};
618             }
619 1         3 return 1
620             }
621              
622             =item B(I<$groupname>)
623              
624             =over 4
625              
626             Returns true if $groupname is available.
627              
628             =back
629              
630             =cut
631              
632             sub groupExists {
633 41     41 1 56 my $group = shift;
634 41 50       74 unless (defined $group) {
635 0 0       0 warn "group not specified or is not defined" if $verbose;
636 0         0 return 0
637             }
638 41 100       68 unless (exists $groups{$group}) {
639 1 50       4 warn "group $group does not exist" if $verbose;
640 1         4 return 0
641             }
642 40         89 return 1
643             }
644              
645             =item B(I<$groupname>)
646              
647             =over 4
648              
649             Returns the list of existing members of $groupname. It will return an empty list
650             if $groupname equals 'main'.
651              
652             =back
653              
654             =cut
655              
656             sub groupMembers {
657 2     2 1 11 my $group = shift;
658 2 50       4 if (groupExists($group)) {
659 2 50       5 if ($group eq 'main') {
660 0         0 warn "no access to main group members";
661             return ()
662 0         0 }
663 2         3 my $l = $groups{$group}->[0];
664 2         5 return @$l;
665             }
666             }
667              
668             =item B(I<$groupname>, I<@newmembers>)
669              
670             =over 4
671              
672             Adds new members to $groupname. You cannot add members to the 'main' group.
673              
674             =back
675              
676             =cut
677              
678             sub groupMembersAdd {
679 1     1 1 386 my $group = shift;
680 1 50       3 if (groupExists($group)) {
681 1 50       5 if ($group eq 'main') {
682 0         0 warn "no access to main group members";
683             return
684 0         0 }
685 1         3 my $l = $groups{$group}->[0];
686 1         5 push @$l, @_;
687             }
688             }
689              
690             =item B(I<$groupname>, I<@members>)
691              
692             =over 4
693              
694             Replaces the list of members in $groupsname by @members. You cannot modify the members list of the 'main' group.
695              
696             =back
697              
698             =cut
699              
700             sub groupMembersReplace {
701 1     1 1 285 my $group = shift;
702 1 50       4 if (groupExists($group)) {
703 1 50       4 if ($group eq 'main') {
704 0         0 warn "No access to main group members";
705             return
706 0         0 }
707 1         4 my $l = $groups{$group}->[0];
708 1         5 @$l = @_;
709             }
710             }
711              
712             =item B(I<$groupname>, I<$option>, ?I<$value>?)
713              
714             =over 4
715              
716             Sets and returns the value of $option in $groupname. $value should be a corresponding key from
717             the Gtk hash. If that key is not found, it assumes a direct value.
718              
719             =back
720              
721             =cut
722              
723             sub groupOption {
724 29     29 1 328 my $group = shift;
725 29 50       42 if (groupExists($group)) {
726 29         36 my $option = shift;
727 29 50       48 unless (defined $option) {
728 0 0       0 warn "option not defined or specified" if $verbose;
729             return
730 0         0 }
731 29 100       61 if (@_) {
732 27         33 my $value = shift;
733 27         69 $groups{$group}->[1]->{$option} = $value;
734             }
735 29         64 return $groups{$group}->[1]->{$option}
736             }
737             }
738              
739             =item B(I<$groupname>)
740              
741             =over 4
742              
743             Returns a list of all available options in $groupname.
744              
745             =back
746              
747             =cut
748              
749             sub groupOptionAll {
750 2     2 1 287 my $group = shift;
751 2 50       6 if (groupExists($group)) {
752 2         6 my $opt = $groups{$group}->[1];
753 2         8 return keys %$opt
754             }
755             }
756              
757             =item B(I<$groupname>, I<$option>)
758              
759             =over 4
760              
761             Removes $option from $groupname
762              
763             =back
764              
765             =cut
766              
767             sub groupOptionDelete {
768 1     1 1 277 my $group = shift;
769 1 50       4 if (groupExists($group)) {
770 1         3 my $option = shift;
771 1 50       4 unless (defined $option) {
772 0 0       0 warn "option not defined or specified" if $verbose;
773             return
774 0         0 }
775 1         3 delete $groups{$group}->[1]->{$option};
776             }
777             }
778              
779             =item B(I<$key>, ?I<$value>?)
780              
781             =over 4
782              
783             Sets and returns the value of $key in the Gtk hash
784              
785             =back
786              
787             =cut
788              
789             sub gtkKey {
790 45     45 1 73 my ($key, $val) = @_;
791 45 50       72 return undef if $no_gtk;
792 45 100       85 $gtksettings{$key} = $val if defined $val;
793 45 100       75 if (exists $gtksettings{$key}) {
794 43         89 return $gtksettings{$key}
795             } else {
796 2 50       4 warn "item $key not present in gtk settings" if $verbose;
797             }
798             return undef
799 2         6 }
800              
801             =item B
802              
803             =over 4
804              
805             Returns a list of all available keys in the Gtk hash.
806              
807             =back
808              
809             =cut
810              
811             sub gtkKeyAll {
812 0 0   0 1 0 return 0 if $no_gtk;
813 0         0 return keys %gtksettings
814             }
815              
816             =item B(I<$key>)
817              
818             =over 4
819              
820             Delets $key from the Gtk hash.
821              
822             =back
823              
824             =cut
825              
826             sub gtkKeyDelete {
827 1     1 1 4 my $key = shift;
828 1 50       3 return 0 if $no_gtk;
829 1 50       4 if (exists $gtksettings{$key}) {
830 1         3 delete $gtksettings{$key}
831             } else {
832 0 0       0 warn "item $key not present in gtk settings" if $verbose;
833             }
834             }
835              
836             =item B
837              
838             =over 4
839              
840             Initializes some sensible defaults. Also does a full reset and loads Gtk configuration files.
841              
842             =back
843              
844             =cut
845              
846             sub initDefaults {
847 2 50   2 1 467 return unless platformPermitted;
848 2         11 resetAll;
849 2         7 loadGtkInfo;
850 2         8 gtkKey('tk-active-background', alterColor(gtkKey('theme_bg_color'), 30));
851 2         6 gtkKey('tk-through-color', alterColor(gtkKey('theme_bg_color'), 30));
852 2         17 for (keys %mainoptions) {
853 26         41 groupOption('main', $_, $mainoptions{$_})
854             }
855 2         8 my @cw = @contentwidgets;
856 2         8 my %co = %contentoptions;
857 2         10 groupAdd('content', \@cw, \%co);
858 2         6 my @lw = @listwidgets;
859 2         7 my %lo = %listoptions;
860 2         15 groupAdd('list', \@lw, \%lo);
861 2         8 groupAdd('menu', ['Menu'], {borderWidth => 1});
862             }
863              
864             =item B(I<$hex_color>)
865              
866             =over 4
867              
868             Returns and array with the decimal values of red, green and blue.
869              
870             =back
871              
872             =cut
873              
874             sub hex2rgb {
875 6     6 1 13 my $hex = shift;
876 6         25 $hex =~ s/^(\#|Ox)//;
877 6         10 $_ = $hex;
878 6         28 my ($r, $g, $b) = m/(\w{2})(\w{2})(\w{2})/;
879 6         15 my @rgb = ();
880 6         14 $rgb[0] = CORE::hex($r);
881 6         8 $rgb[1] = CORE::hex($g);
882 6         10 $rgb[2] = CORE::hex($b);
883             return @rgb
884 6         16 }
885              
886             =item B(I<$num>)
887              
888             =over 4
889              
890             Return the hexadecimal representation of $num in a two character string.
891              
892             =back
893              
894             =cut
895              
896             sub hexstring {
897 19     19 1 276 my $num = shift;
898 19         54 my $hex = substr(sprintf("0x%X", $num), 2);
899 19 100       40 if (length($hex) < 2) { $hex = "0$hex" }
  5         7  
900 19         35 return $hex
901             }
902              
903             =item B
904              
905             =over 4
906              
907             Empties the Gtk hash and (re)loads the Gtk configuration files.
908              
909             =back
910              
911             =cut
912              
913             sub loadGtkInfo {
914 2 50   2 1 5 return unless platformPermitted;
915 2         21 %gtksettings = ();
916 2         5 my $cf = $gtkpath . "colors.css";
917 2 50       91 if (open(OFILE, "<", $cf)) {
918 2         76 while () {
919 140         234 my $line = $_;
920 140 50       517 if ($line =~ s/\@define-color\s//) {
921 140 50       455 if ($line =~ /([^\s]+)\s([^;]+);/) {
922 140         253 my $key = $1;
923 140         196 my $color = $2;
924 140 50       241 $color = convertColorCode($color) if $color =~ /^rgb\(/;
925 140         214 $key = _truncate($key);
926 140         469 $gtksettings{$key} = $color
927             }
928             }
929             }
930 2         37 close OFILE
931             } else {
932 0 0       0 warn "cannot open Gtk colors.css" if $verbose;
933 0         0 $no_gtk = 1;
934             }
935 2         8 my $sf = $gtkpath . "settings.ini";
936 2 50       84 if (open(OFILE, "<", $sf)) {
937 2         60 while () {
938 24         40 my $line = $_;
939 24 100       86 if ($line =~ /([^=]+)=([^\n]+)/) {
940 22         101 $gtksettings{$1} = $2
941             }
942             }
943 2         20 close OFILE;
944 2 50       10 if (exists $gtksettings{'gtk-font-name'}) {
945 2         8 my $font = decodeFont($gtksettings{'gtk-font-name'});
946 2         11 $gtksettings{'gtk-font-name'} = $font;
947             }
948             } else {
949 0 0       0 warn "cannot open Gtk settings.ini" if $verbose;
950 0         0 $no_gtk = 1;
951             }
952             }
953              
954             =item B
955              
956             =over 4
957              
958             Returns true if you are not on Windows or Mac.
959              
960             =back
961              
962             =cut
963              
964             sub platformPermitted {
965 7     7 1 24 my $platform = $^O;
966 7 50 33     116 return 0 if (($Config{osname} eq 'MSWin32') or ($Config{osname} eq 'darwin'));
967 7         28 return 1
968             }
969              
970             =item B(I<$file>)
971              
972             =over 4
973              
974             Same as export2file($file, 1)
975              
976             =back
977              
978             =cut
979              
980             sub removeFromfile {
981 0     0 1 0 my $f = shift;
982 0         0 export2file($f, 1);
983             }
984              
985             =item B
986              
987             =over 4
988              
989             Same as export2Xdefaults(1)
990              
991             =back
992              
993             =cut
994              
995             sub removeFromXdefaults {
996 0     0 1 0 export2file('~/.Xdefaults', 1);
997             }
998              
999             =item B
1000              
1001             =over 4
1002              
1003             Same as export2Xresources(1)
1004              
1005             =back
1006              
1007             =cut
1008              
1009             sub removeFromXresources {
1010 0     0 1 0 export2file('~/.Xresouces', 1);
1011             }
1012              
1013             =item B
1014              
1015             =over 4
1016              
1017             Removes all the settings previously defined from the xrdb database
1018              
1019             =back
1020              
1021             =cut
1022              
1023             sub removeFromxrdb {
1024 0 0   0 1 0 return unless platformPermitted;
1025 0 0       0 return if $no_gtk;
1026 0 0       0 if (open(OFILE, ">", $out_file)) {
1027 0         0 print OFILE generateOutput;
1028 0         0 close OFILE;
1029 0         0 system "xrdb -remove $out_file";
1030 0 0       0 unlink $out_file if $delete_output;
1031             }
1032             }
1033              
1034             =item B
1035              
1036             =over 4
1037              
1038             Removes all groups and options. The group 'main' will remain, but all its options are also deleted.
1039             This does not affect the Gtk hash.
1040              
1041             =back
1042              
1043             =cut
1044              
1045             sub resetAll {
1046 2     2 1 17 %groups = (
1047             main => [[''], {}]
1048             )
1049             }
1050              
1051             =item B(I<$red>, I<$green>, I<$blue>)
1052              
1053             =over 4
1054              
1055             Converts the decimval values $red, $green and $blue into a hex color string.
1056              
1057             =back
1058              
1059             =cut
1060              
1061             sub rgb2hex {
1062 6     6 1 276 my ($red, $green, $blue) = @_;
1063 6         21 my $r = hexstring($red);
1064 6         11 my $g = hexstring($green);
1065 6         16 my $b = hexstring($blue);
1066 6         25 return "#$r$g$b"
1067              
1068             }
1069              
1070             sub _truncate {
1071 140     140   204 my $name = shift;
1072 140         208 for (@basegtkeys) {
1073 3734         4615 my $key = $_;
1074 3734 100       6680 if (substr($name, 0, length($key)) eq $key) {
1075 140         252 return $key
1076             }
1077             }
1078 0           return $name
1079             }
1080              
1081             =back
1082              
1083             =head1 COPYRIGHT AND LICENSE
1084              
1085             Copyright 2022 by Hans Jeuken
1086              
1087             GPL v3.0 or same as Perl, in your option.
1088              
1089             =head1 AUTHOR
1090              
1091             Hans Jeuken (jeuken dot hans at gmail dot com)
1092              
1093             =head1 BUGS AND CAVEATS
1094              
1095             Exporting to xrdb will not work if the name of your executable/script contains
1096             an extension (.pl). This is a limitation of xrdb.
1097              
1098             If you find any bugs, please contact the author.
1099              
1100             =head1 TODO
1101              
1102             =cut
1103              
1104              
1105             1;
1106             __END__