1 /*
2  * XKb Switch API for using in vim libcall()
3  *
4  * Copyright (C) 2013 by Alexei Rad'kov
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  */
11 
12 #include <algorithm>
13 #include "XKeyboard.hpp"
14 
15 using namespace std;
16 using namespace kb;
17 
18 namespace
19 {
20     class  XKeyboardWrapper
21     {
22         public:
XKeyboardWrapper()23             XKeyboardWrapper() : xkb( NULL ), unusable( false )
24             {}
25 
~XKeyboardWrapper()26             ~XKeyboardWrapper()
27             {
28                 delete xkb;
29             }
30 
get(void)31             XKeyboard *  get( void )
32             {
33                 if ( unusable )
34                     return NULL;
35 
36                 if ( xkb )
37                     return xkb;
38 
39                 try
40                 {
41                     xkb = new XKeyboard((size_t)(-1));
42                     xkb->open_display();
43                 }
44                 catch( ... )
45                 {
46                     unusable = true;
47                     return NULL;
48                 }
49 
50                 return xkb;
51             }
52 
53         private:
54             XKeyboard *  xkb;
55             bool         unusable;
56 
57     }  xkb;
58 
59     string_vector  symNames;
60 
getSymNames(void)61     string_vector &  getSymNames( void )
62     {
63         static bool  loaded = false;
64 
65         if ( loaded )
66             return symNames;
67 
68         XKeyboard *  xkb = ::xkb.get();
69 
70         if ( ! xkb )
71         {
72             loaded = true;
73             return symNames;
74         }
75 
76         loaded = true;
77         xkb->build_layout(symNames);
78         return symNames;
79     }
80 }
81 
82 
83 extern "C"
84 {
Xkb_Switch_getXkbLayout(const char *)85     const char *  Xkb_Switch_getXkbLayout( const char *  /* unused */ )
86     {
87         try
88         {
89             XKeyboard *  xkb = ::xkb.get();
90 
91             if ( ! xkb )
92                 return "";
93 
94             string_vector &  syms = getSymNames();
95 
96             return syms.at( xkb->get_group() ).c_str();
97         }
98         catch( ... )
99         {
100         }
101 
102         return NULL;
103     }
104 
105 
Xkb_Switch_setXkbLayout(const char * newgrp)106     const char *  Xkb_Switch_setXkbLayout( const char *  newgrp )
107     {
108         try
109         {
110             XKeyboard *  xkb = ::xkb.get();
111 
112             if ( ! xkb )
113                 return "";
114 
115             string_vector &  syms = getSymNames();
116 
117             if ( newgrp == NULL || newgrp[ 0 ] == '\0' )
118                 return NULL;
119 
120             string_vector::iterator  i = find( syms.begin(), syms.end(),
121                                                newgrp );
122 
123             if ( i == syms.end() )
124                return NULL;
125 
126             xkb->set_group( i - syms.begin() );
127         }
128         catch( ... )
129         {
130         }
131 
132         return NULL;
133     }
134 }
135 
136