File Coverage

blib/lib/Tk/GtkSettings.pm
Criterion Covered Total %
statement 222 276 80.4
branch 79 164 48.1
condition 1 3 33.3
subroutine 31 40 77.5
pod 34 34 100.0
total 367 517 70.9


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   62454 use strict;
  1         2  
  1         24  
10 1     1   5 use warnings;
  1         2  
  1         19  
11 1     1   4 use File::Basename;
  1         2  
  1         79  
12 1     1   5 use Config;
  1         1  
  1         32  
13             our $VERSION = '0.06';
14              
15 1     1   5 use Exporter;
  1         1  
  1         3382  
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($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 133 my ($hex, $offset) = @_;
311 5         10 my @rgb = hex2rgb($hex);
312 5         8 my @rgba = ();
313 5         10 for (@rgb) {
314 15 100       24 if ($_ < 128) {
315 3         5 my $c = $_ + $offset;
316 3 50       5 $c = 0 if $c < 0;
317 3         5 push @rgba, $c
318             } else {
319 12         16 my $c = $_ - $offset;
320 12 50       20 $c = 255 if $c > 255;
321 12         20 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         20 $app_name = basename($app_name); #remove leading folders
361 1         4 $app_name =~ s/\.[^.]+$//; #remove extension
362 1         3 $marker = "!$app_name Tk::GtkSettings section\n";
363             }
364 1         2 return $app_name
365             }
366              
367             =item B(I<'rgb(255, 0, 0)'>)
368              
369             =over 4
370              
371             Some color settings in the Gtk configuration files are in the format 'rgb(255, 255, 255)'.
372             B converts these to a hex color string.
373              
374             =back
375              
376             =cut
377              
378             sub convertColorCode {
379 1     1 1 590 my $input = shift;
380 1 50       20 if ($input =~ /rgb\((\d+),(\d+),(\d+)\)/) {
381 1         8 my $r = substr(sprintf("0x%X", $1), 2);
382 1         5 my $g = substr(sprintf("0x%X", $2), 2);
383 1         4 my $b = substr(sprintf("0x%X", $3), 2);
384 1         16 return "#$r$g$b"
385             }
386             }
387              
388             =item B(I<$gtkfontstring>)
389              
390             =over 4
391              
392             Converts the font string in gtk to something Tk can handle
393              
394             =back
395              
396             =cut
397              
398             sub decodeFont {
399 2     2 1 4 my $rawfont = shift;
400 2         3 my $family = '';
401 2         4 my $style = '';
402 2         3 my $size = '';
403 2 50       13 if ($rawfont =~ s/^([^,]+),//) {
404 2         7 $family = $1;
405             }
406 2         7 $rawfont =~ s/^\s*//; #remove leading spaces
407 2 50       7 if ($rawfont =~ s/^([^\d]+)//) {
408 0         0 $style = $1;
409 0         0 $style =~ s/^\s*//; #remove leading spaces
410 0         0 $style =~ s/\s*!//; #remove trailing spaces
411 0         0 $style = lc($style);
412             }
413 2 50       9 if ($rawfont =~ s/^(\d+)//) {
414 2         5 $size = $1;
415 2         4 $size =~ s/\s*!//; #remove trailing spaces
416             }
417 2         8 return "{$family} $size $style"
418             }
419              
420             =item B(I<$file>, ?I<$removeflag>?)
421              
422             =over 4
423              
424             Exports your Gtk settings to $file in a format recognized by xrdb. It looks for a section
425             in the file marked by appName . "Tk::GtkSettings section\n". If it finds it it will replace this section.
426             Otherwise it will append your Gtk settings to the end of the file. If $file does not yet exist it
427             will create it. if $removeflag is true it will not export but remove the section from $file.
428              
429             =back
430              
431             =cut
432              
433             sub export2file {
434 2     2 1 7 my ($file, $remove) = @_;
435 2 100       7 $remove = 0 unless defined $remove;
436 2         4 my $out = "";
437 2         3 my $found = 0;
438 2 50       30 if (-e $file) {
439 2 50       60 unless (open(XDEF, "<$file")) {
440 0 0       0 warn "cannot open $file" if $verbose;
441             return
442 0         0 }
443 2         8 my $inside = 0;
444 2         50 while (my $l = ) {
445 53 100       84 if ($inside) {
446 36 100       75 if ($l eq $marker) {
447 1         2 $inside = 0;
448             }
449             } else {
450 17 100       27 if ($l eq $marker) {
451 1         3 $inside = 1;
452 1         2 $found = 1;
453 1 50       4 $out = "$out$l" . generateOutput . $l unless $remove;
454             } else {
455 16         50 $out = "$out$l";
456             }
457             }
458             }
459 2         21 close XDEF;
460             }
461 2 100       8 unless ($found) {
462 1         6 $out = "$out\n$marker" . generateOutput . "$marker\n"
463             }
464 2 50       124 unless (open(XDEFO, ">$file")) {
465 0 0       0 warn "cannot open $file" if $verbose;
466             return
467 0         0 }
468 2         32 print XDEFO $out;
469 2         179 close XDEFO;
470             }
471              
472             =item B(?I<$removeflag>?)
473              
474             =over 4
475              
476             Same as B, however the file is always '~/.Xdefaults'.
477              
478             =back
479              
480             =cut
481              
482             sub export2Xdefaults {
483 0     0 1 0 export2file('~/.Xdefaults');
484             }
485              
486             =item B(?I<$removeflag>?)
487              
488             =over 4
489              
490             Same as B, however the file is always '~/.Xresources'.
491              
492             =back
493              
494             =cut
495              
496             sub export2Xresources {
497 0     0 1 0 export2file('~/.Xresources');
498             }
499              
500             =item B
501              
502             =over 4
503              
504             exports your Gtk settings directly to the xrdb database.
505              
506             =back
507              
508             =cut
509              
510             sub export2xrdb {
511 0 0   0 1 0 return unless platformPermitted;
512 0 0       0 return if $no_gtk;
513 0 0       0 if (open(OFILE, ">", $out_file)) {
514 0         0 print OFILE generateOutput;
515 0         0 close OFILE;
516 0         0 system "xrdb $out_file";
517 0 0       0 unlink $out_file if $delete_output;
518             }
519             }
520              
521             =item B
522              
523             =over 4
524              
525             Generates the output used by the export functions. Returns a string.
526              
527             =back
528              
529             =cut
530              
531             sub generateOutput {
532 1 50   1 1 3 return if $no_gtk;
533 1 50       3 return unless platformPermitted;
534 1         3 my $output = '';
535             #group main has to be done first.
536 1         3 my (@g) = ('main');
537 1         7 for (sort keys %groups) {
538 4 100       10 push @g, $_ unless $_ eq 'main';
539             }
540 1         4 for (@g) {
541 4         6 my $name = $_;
542 4         7 my $group = $groups{$name};
543 4         6 my $options = $group->[1];
544 4         5 my $mem = $group->[0];
545 4         7 for (@$mem) {
546 13         14 my $member = $_;
547 13         35 for (sort keys %$options) {
548 35         62 my $val = gtkKey($options->{$_});
549 35 100       60 $val = $options->{$_} unless defined $val;
550 35 100       54 unless ($name eq 'main') {
551 22         65 $output = $output . $app_name . "*$member." . $_ . ": " . $val . "\n";
552             } else {
553 13         44 $output = $output . $app_name . '*' . $_ . ": " . $val . "\n";
554             }
555             }
556             }
557             }
558 1         20 return $output
559             }
560              
561             =item B(I<$groupname>, I<\@members>, I<\%options>)
562              
563             =over 4
564              
565             Adds $groupname to the groups hash. If @members or %options are not specified,
566             it will leave them empty.
567              
568             =back
569              
570             =cut
571              
572             sub groupAdd {
573 7     7 1 281 my ($group, $members, $options) = @_;
574 7 50       13 unless (defined $group) {
575 0 0       0 warn "group is not defined" if $verbose;
576             return
577 0         0 }
578 7 50       21 $members = [] unless defined $members;
579 7 50       12 $options = {} unless defined $options;
580 7 50       15 unless (exists $groups{$group}) {
581 7         24 $groups{$group} = [$members, $options]
582             } else {
583 0 0       0 warn "group $group already exists" if $verbose
584             }
585             }
586              
587             =item B
588              
589             =over 4
590              
591             Returns a list of all available groups.
592              
593             =back
594              
595             =cut
596              
597             sub groupAll {
598 1     1 1 8 return keys %groups
599             }
600              
601             =item B(I<$groupname>)
602              
603             =over 4
604              
605             Removes $groupsname from the groups hash. You cannot delete the 'main' group.
606              
607             =back
608              
609             =cut
610              
611             sub groupDelete {
612 2     2 1 5 my $group = shift;
613 2 50       3 if (groupExists($group)) {
614 2 100       11 if ($group eq 'main') {
615 1 50       4 warn "deleting main group is not allowed" if $verbose;
616 1         3 return 0
617             }
618 1         3 delete $groups{$group};
619             }
620 1         3 return 1
621             }
622              
623             =item B(I<$groupname>)
624              
625             =over 4
626              
627             Returns true if $groupname is available.
628              
629             =back
630              
631             =cut
632              
633             sub groupExists {
634 41     41 1 59 my $group = shift;
635 41 50       72 unless (defined $group) {
636 0 0       0 warn "group not specified or is not defined" if $verbose;
637 0         0 return 0
638             }
639 41 100       70 unless (exists $groups{$group}) {
640 1 50       39 warn "group $group does not exist" if $verbose;
641 1         7 return 0
642             }
643 40         103 return 1
644             }
645              
646             =item B(I<$groupname>)
647              
648             =over 4
649              
650             Returns the list of existing members of $groupname. It will return an empty list
651             if $groupname equals 'main'.
652              
653             =back
654              
655             =cut
656              
657             sub groupMembers {
658 2     2 1 9 my $group = shift;
659 2 50       4 if (groupExists($group)) {
660 2 50       6 if ($group eq 'main') {
661 0         0 warn "no access to main group members";
662             return ()
663 0         0 }
664 2         3 my $l = $groups{$group}->[0];
665 2         7 return @$l;
666             }
667             }
668              
669             =item B(I<$groupname>, I<@newmembers>)
670              
671             =over 4
672              
673             Adds new members to $groupname. You cannot add members to the 'main' group.
674              
675             =back
676              
677             =cut
678              
679             sub groupMembersAdd {
680 1     1 1 353 my $group = shift;
681 1 50       3 if (groupExists($group)) {
682 1 50       5 if ($group eq 'main') {
683 0         0 warn "no access to main group members";
684             return
685 0         0 }
686 1         2 my $l = $groups{$group}->[0];
687 1         4 push @$l, @_;
688             }
689             }
690              
691             =item B(I<$groupname>, I<@members>)
692              
693             =over 4
694              
695             Replaces the list of members in $groupsname by @members. You cannot modify the members list of the 'main' group.
696              
697             =back
698              
699             =cut
700              
701             sub groupMembersReplace {
702 1     1 1 291 my $group = shift;
703 1 50       4 if (groupExists($group)) {
704 1 50       4 if ($group eq 'main') {
705 0         0 warn "No access to main group members";
706             return
707 0         0 }
708 1         3 my $l = $groups{$group}->[0];
709 1         4 @$l = @_;
710             }
711             }
712              
713             =item B(I<$groupname>, I<$option>, ?I<$value>?)
714              
715             =over 4
716              
717             Sets and returns the value of $option in $groupname. $value should be a corresponding key from
718             the Gtk hash. If that key is not found, it assumes a direct value.
719              
720             =back
721              
722             =cut
723              
724             sub groupOption {
725 29     29 1 320 my $group = shift;
726 29 50       41 if (groupExists($group)) {
727 29         40 my $option = shift;
728 29 50       54 unless (defined $option) {
729 0 0       0 warn "option not defined or specified" if $verbose;
730             return
731 0         0 }
732 29 100       42 if (@_) {
733 27         45 my $value = shift;
734 27         53 $groups{$group}->[1]->{$option} = $value;
735             }
736 29         62 return $groups{$group}->[1]->{$option}
737             }
738             }
739              
740             =item B(I<$groupname>)
741              
742             =over 4
743              
744             Returns a list of all available options in $groupname.
745              
746             =back
747              
748             =cut
749              
750             sub groupOptionAll {
751 2     2 1 282 my $group = shift;
752 2 50       6 if (groupExists($group)) {
753 2         5 my $opt = $groups{$group}->[1];
754 2         8 return keys %$opt
755             }
756             }
757              
758             =item B(I<$groupname>, I<$option>)
759              
760             =over 4
761              
762             Removes $option from $groupname
763              
764             =back
765              
766             =cut
767              
768             sub groupOptionDelete {
769 1     1 1 277 my $group = shift;
770 1 50       3 if (groupExists($group)) {
771 1         3 my $option = shift;
772 1 50       3 unless (defined $option) {
773 0 0       0 warn "option not defined or specified" if $verbose;
774             return
775 0         0 }
776 1         4 delete $groups{$group}->[1]->{$option};
777             }
778             }
779              
780             =item B(I<$key>, ?I<$value>?)
781              
782             =over 4
783              
784             Sets and returns the value of $key in the Gtk hash
785              
786             =back
787              
788             =cut
789              
790             sub gtkKey {
791 46     46 1 71 my ($key, $val) = @_;
792 46 50       78 return undef if $no_gtk;
793 46 100       85 $gtksettings{$key} = $val if defined $val;
794 46 100       82 if (exists $gtksettings{$key}) {
795 43         90 return $gtksettings{$key}
796             } else {
797 3 50       5 warn "item $key not present in gtk settings" if $verbose;
798             }
799             return undef
800 3         9 }
801              
802             =item B
803              
804             =over 4
805              
806             Returns a list of all available keys in the Gtk hash.
807              
808             =back
809              
810             =cut
811              
812             sub gtkKeyAll {
813 0 0   0 1 0 return 0 if $no_gtk;
814 0         0 return keys %gtksettings
815             }
816              
817             =item B(I<$key>)
818              
819             =over 4
820              
821             Delets $key from the Gtk hash.
822              
823             =back
824              
825             =cut
826              
827             sub gtkKeyDelete {
828 1     1 1 3 my $key = shift;
829 1 50       4 return 0 if $no_gtk;
830 1 50       4 if (exists $gtksettings{$key}) {
831 1         2 delete $gtksettings{$key}
832             } else {
833 0 0       0 warn "item $key not present in gtk settings" if $verbose;
834             }
835             }
836              
837             =item B
838              
839             =over 4
840              
841             Initializes some sensible defaults. Also does a full reset and loads Gtk configuration files.
842              
843             =back
844              
845             =cut
846              
847             sub initDefaults {
848 2 50   2 1 481 return unless platformPermitted;
849 2         10 resetAll;
850 2         7 loadGtkInfo;
851 2         7 gtkKey('tk-active-background', alterColor(gtkKey('theme_bg_color'), 30));
852 2         6 gtkKey('tk-through-color', alterColor(gtkKey('theme_bg_color'), 30));
853 2         11 for (keys %mainoptions) {
854 26         41 groupOption('main', $_, $mainoptions{$_})
855             }
856 2         9 my @cw = @contentwidgets;
857 2         7 my %co = %contentoptions;
858 2         10 groupAdd('content', \@cw, \%co);
859 2         6 my @lw = @listwidgets;
860 2         8 my %lo = %listoptions;
861 2         6 groupAdd('list', \@lw, \%lo);
862 2         7 groupAdd('menu', ['Menu', 'NoteBook'], {borderWidth => 1});
863             }
864              
865             =item B(I<$hex_color>)
866              
867             =over 4
868              
869             Returns and array with the decimal values of red, green and blue.
870              
871             =back
872              
873             =cut
874              
875             sub hex2rgb {
876 6     6 1 12 my $hex = shift;
877 6         28 $hex =~ s/^(\#|Ox)//;
878 6         13 $_ = $hex;
879 6         27 my ($r, $g, $b) = m/(\w{2})(\w{2})(\w{2})/;
880 6         12 my @rgb = ();
881 6         12 $rgb[0] = CORE::hex($r);
882 6         10 $rgb[1] = CORE::hex($g);
883 6         8 $rgb[2] = CORE::hex($b);
884             return @rgb
885 6         16 }
886              
887             =item B(I<$num>)
888              
889             =over 4
890              
891             Return the hexadecimal representation of $num in a two character string.
892              
893             =back
894              
895             =cut
896              
897             sub hexstring {
898 19     19 1 319 my $num = shift;
899 19         52 my $hex = substr(sprintf("0x%X", $num), 2);
900 19 100       35 if (length($hex) < 2) { $hex = "0$hex" }
  5         9  
901 19         37 return $hex
902             }
903              
904             =item B
905              
906             =over 4
907              
908             Empties the Gtk hash and (re)loads the Gtk configuration files.
909              
910             =back
911              
912             =cut
913              
914             sub loadGtkInfo {
915 2 50   2 1 6 return unless platformPermitted;
916 2         16 %gtksettings = ();
917 2         6 my $cf = $gtkpath . "colors.css";
918 2 50       88 if (open(OFILE, "<", $cf)) {
919 2         65 while () {
920 140         229 my $line = $_;
921 140 50       536 if ($line =~ s/\@define-color\s//) {
922 140 50       535 if ($line =~ /([^\s]+)\s([^;]+);/) {
923 140         257 my $key = $1;
924 140         207 my $color = $2;
925 140 50       246 $color = convertColorCode($color) if $color =~ /^rgb\(/;
926 140         220 $key = _truncate($key);
927 140         510 $gtksettings{$key} = $color
928             }
929             }
930             }
931 2         24 close OFILE
932             } else {
933 0 0       0 warn "cannot open Gtk colors.css" if $verbose;
934 0         0 $no_gtk = 1;
935             }
936 2         9 my $sf = $gtkpath . "settings.ini";
937 2 50       74 if (open(OFILE, "<", $sf)) {
938 2         45 while () {
939 24         46 my $line = $_;
940 24 100       87 if ($line =~ /([^=]+)=([^\n]+)/) {
941 22         96 $gtksettings{$1} = $2
942             }
943             }
944 2         19 close OFILE;
945 2 50       10 if (exists $gtksettings{'gtk-font-name'}) {
946 2         7 my $font = decodeFont($gtksettings{'gtk-font-name'});
947 2         7 $gtksettings{'gtk-font-name'} = $font;
948             }
949             } else {
950 0 0       0 warn "cannot open Gtk settings.ini" if $verbose;
951 0         0 $no_gtk = 1;
952             }
953             }
954              
955             =item B
956              
957             =over 4
958              
959             Returns true if you are not on Windows or Mac.
960              
961             =back
962              
963             =cut
964              
965             sub platformPermitted {
966 7     7 1 23 my $platform = $^O;
967 7 50 33     98 return 0 if (($Config{osname} eq 'MSWin32') or ($Config{osname} eq 'darwin'));
968 7         32 return 1
969             }
970              
971             =item B(I<$file>)
972              
973             =over 4
974              
975             Same as export2file($file, 1)
976              
977             =back
978              
979             =cut
980              
981             sub removeFromfile {
982 0     0 1 0 my $f = shift;
983 0         0 export2file($f, 1);
984             }
985              
986             =item B
987              
988             =over 4
989              
990             Same as export2Xdefaults(1)
991              
992             =back
993              
994             =cut
995              
996             sub removeFromXdefaults {
997 0     0 1 0 export2file('~/.Xdefaults', 1);
998             }
999              
1000             =item B
1001              
1002             =over 4
1003              
1004             Same as export2Xresources(1)
1005              
1006             =back
1007              
1008             =cut
1009              
1010             sub removeFromXresources {
1011 0     0 1 0 export2file('~/.Xresouces', 1);
1012             }
1013              
1014             =item B
1015              
1016             =over 4
1017              
1018             Removes all the settings previously defined from the xrdb database
1019              
1020             =back
1021              
1022             =cut
1023              
1024             sub removeFromxrdb {
1025 0 0   0 1 0 return unless platformPermitted;
1026 0 0       0 return if $no_gtk;
1027 0 0       0 if (open(OFILE, ">", $out_file)) {
1028 0         0 print OFILE generateOutput;
1029 0         0 close OFILE;
1030 0         0 system "xrdb -remove $out_file";
1031 0 0       0 unlink $out_file if $delete_output;
1032             }
1033             }
1034              
1035             =item B
1036              
1037             =over 4
1038              
1039             Removes all groups and options. The group 'main' will remain, but all its options are also deleted.
1040             This does not affect the Gtk hash.
1041              
1042             =back
1043              
1044             =cut
1045              
1046             sub resetAll {
1047 2     2 1 16 %groups = (
1048             main => [[''], {}]
1049             )
1050             }
1051              
1052             =item B(I<$red>, I<$green>, I<$blue>)
1053              
1054             =over 4
1055              
1056             Converts the decimval values $red, $green and $blue into a hex color string.
1057              
1058             =back
1059              
1060             =cut
1061              
1062             sub rgb2hex {
1063 6     6 1 257 my ($red, $green, $blue) = @_;
1064 6         11 my $r = hexstring($red);
1065 6         12 my $g = hexstring($green);
1066 6         33 my $b = hexstring($blue);
1067 6         21 return "#$r$g$b"
1068              
1069             }
1070              
1071             sub _truncate {
1072 140     140   205 my $name = shift;
1073 140         233 for (@basegtkeys) {
1074 3734         4598 my $key = $_;
1075 3734 100       6895 if (substr($name, 0, length($key)) eq $key) {
1076 140         265 return $key
1077             }
1078             }
1079 0           return $name
1080             }
1081              
1082             =back
1083              
1084             =head1 COPYRIGHT AND LICENSE
1085              
1086             Copyright 2022 - 2023 by Hans Jeuken
1087              
1088             Same as Perl, in your option.
1089              
1090             =head1 AUTHOR
1091              
1092             Hans Jeuken (jeuken dot hans at gmail dot com)
1093              
1094             =head1 BUGS AND CAVEATS
1095              
1096             If you find any bugs, please contact the author.
1097              
1098             =head1 TODO
1099              
1100             =cut
1101              
1102              
1103             1;
1104             __END__