"Fossies" - the Fresh Open Source Software Archive 
Member "bbkeys-0.9.1/src/KeyClient.cpp" (22 Dec 2008, 14829 Bytes) of package /linux/privat/old/bbkeys-0.9.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "KeyClient.cpp" see the
Fossies "Dox" file reference documentation.
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // -- KeyClient.cpp --
3 // Copyright (c) 2001 - 2003 Jason 'vanRijn' Kasper <vR at movingparts dot net>
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // E_O_H_VR
24
25 #include "../config.h"
26
27 extern "C" {
28
29 #ifdef HAVE_SIGNAL_H
30 # include <signal.h>
31 #endif // HAVE_SIGNAL_H
32
33 #ifdef HAVE_SYS_SIGNAL_H
34 # include <sys/signal.h>
35 #endif // HAVE_SYS_SIGNAL_H
36
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 # include <sys/types.h>
40 #endif // HAVE_UNISTD_H
41
42 #ifdef HAVE_SYS_STAT_H
43 # include <sys/types.h>
44 # include <sys/stat.h>
45 #endif // HAVE_SYS_STAT_H
46
47 #include <sys/types.h>
48 #include <sys/wait.h>
49
50 }
51
52 #include "version.h"
53
54 #include "KeyClient.h"
55 #include "LocalUtil.h"
56 #include "actions.hh"
57
58 #include <iostream>
59 #include <algorithm>
60 #include <vector>
61 #include <strings.h>
62
63 //--------------------------------------------------------
64 // Constructor/Destructor
65 //--------------------------------------------------------
66 KeyClient::KeyClient (int argc, char **argv,
67 Config & config, std::string display):
68 bt::Application(BBTOOL, display.c_str(), true), _config(config),
69 _keybindings(0), config_check_timer(0)
70 {
71
72 // save off what we're constructed with for reconfiguring later...
73 _argc = argc;
74 _argv = argv;
75
76 // initialize our keyword map for the file tokenizer
77 initKeywords(_keywordMap);
78
79 // now connect to the X server
80 _display = XDisplay();
81 if (! _display ) {
82 cerr << BBTOOL << ": " << "KeyClient: ERROR: Can't connect to X Server. Bummer! Exiting\n";
83 exit(2);
84 }
85
86 // check to see if we've been handed another config-file to use
87 _configFileName = bt::expandTilde(_config.getStringValue("config",
88 "~/.bbkeysrc") );
89
90 struct stat buf;
91 if (0 != stat(_configFileName.c_str(), &buf) ||!S_ISREG(buf.st_mode)) {
92 cerr << BBTOOL << ": " << "KeyClient: ERROR: Couldn't load rc-file: [" << _configFileName
93 << "], falling back to default: [" << DEFAULTRC << "]\n";
94 _configFileName = DEFAULTRC;
95 } else {
96 _last_time_config_changed = buf.st_mtime;
97 }
98
99 _debug = _config.getBoolValue("debug", false);
100
101 // here's our friendly little general-purpose keygrabber
102 _keyGrabber = new KeyGrabber(_display, numLockMask(), scrollLockMask() );
103
104 _netclient = new Netclient(this->display());
105 _active = _clients.end();
106
107 initialize();
108 }
109
110 KeyClient::~KeyClient ()
111 {
112
113 // delete all screens
114 for_each(screenList.begin(), screenList.end(), bt::PointerAssassin());
115
116 if (_keybindings) delete _keybindings;
117 if (_netclient) delete _netclient;
118 if (_keyGrabber) delete _keyGrabber;
119 }
120
121 void KeyClient::initialize() {
122
123 // now, read in our configuration file and set both program settings
124 // and keybindings we're asked to handle
125 handleConfigFile();
126
127 // parse command options again to override what we read in from config file
128 parseOptions( _argc, _argv, _config );
129
130
131 // now create a screen handler for each screen that exists
132 for (unsigned int i = 0; i < bt::Application::display().screenCount(); i++) {
133 ScreenHandler *screen = new ScreenHandler(this, i);
134 if (! screen->isManaged()) {
135 delete screen;
136 continue;
137 }
138
139 screen->initialize();
140
141 // add this screen to our collection
142 screenList.push_back(screen);
143 }
144
145 if (screenList.empty()) {
146 cerr << BBTOOL << ": " << "KeyClient: initialize: no compatible window managers found, aborting.\n";
147 ::exit(3);
148 }
149
150 _autoConfigCheckTimeout = (_config.getNumberValue("autoConfigCheckTimeout", 10)) * 1000;
151 _autoConfig = _config.getBoolValue("autoConfig", true);
152 if (_autoConfig) {
153 if (!config_check_timer) {
154 config_check_timer = new bt::Timer(this, this);
155 }
156 config_check_timer->setTimeout(_autoConfigCheckTimeout);
157 config_check_timer->recurring(True);
158 config_check_timer->start();
159 }
160
161 }
162
163 //--------------------------------------------------------
164 // reconfigure
165 //--------------------------------------------------------
166 void KeyClient::reconfigure ()
167 {
168 std::cout << BBTOOL << ": " <<
169 "KeyClient: reconfigure: hey, goodie! I got a reconfigure request!!\n";
170
171 // delete all screens
172 for_each(screenList.begin(), screenList.end(), bt::PointerAssassin());
173 screenList.clear();
174
175 // initialize and/or clear our config
176 _config.reset();
177
178 // reset our timer
179 if (config_check_timer) {
180 config_check_timer->halt();
181 }
182
183 initialize();
184
185 }
186
187
188 void KeyClient::handleConfigFile() {
189
190 FileTokenizer tokenizer(_keywordMap, _configFileName.c_str());
191
192 // clear off any of our keybindings we have and get them ready to go
193 if (_keybindings) {
194 _keybindings->unloadBindings();
195 } else {
196 _keybindings = new keytree(_display);
197 }
198
199 _keybindings->reset();
200
201 bool _doingConfig = false, _doingKeybindings = false;
202
203 TokenBlock *block = 0;
204 while ((block = tokenizer.next())) {
205 switch (block->tag) {
206 case ConfigOpts::begin: // um, we ignore these. =:)
207 break;
208 case ConfigOpts::end:
209 if (_doingConfig) {
210 _doingConfig = false;
211 }
212 break;
213 case ConfigOpts::config:
214 _doingConfig = true;
215 break;
216 case ConfigOpts::option:
217 if (_debug)
218 cout << BBTOOL << ": " << "got a config option!, setting key: [" << block->name
219 << "] to value: [" << block->data << "]\n";
220
221 _config.setOption(block->name, block->data);
222 break;
223 case ConfigOpts::keybindings:
224 _doingKeybindings = true;
225 setKeybindings(tokenizer);
226
227 if (_debug)
228 _keybindings->showTree();
229
230 break;
231 default:
232 cerr << BBTOOL << ": " << "unknown tag found in ConfigOpts block: ["
233 << block->tag << "], name: [" << block->name
234 << "], data: [" << block->data << "]\n";
235 break;
236 }
237 delete block;
238 }
239
240 if (_debug) {
241 cout << "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n";
242 _config.showOptions();
243 }
244
245 }
246
247 void KeyClient::setKeybindings(FileTokenizer & tokenizer) {
248
249 // our modifier masks
250 struct {
251 const char *str;
252 unsigned int mask;
253 }
254 modifiers[] = {
255 { "mod1", Mod1Mask },
256 { "mod2", Mod2Mask },
257 { "mod3", Mod3Mask },
258 { "mod4", Mod4Mask },
259 { "mod5", Mod5Mask },
260 { "control", ControlMask },
261 { "shift", ShiftMask },
262 { "", 0 }
263 };
264
265 // this tells us how many levels deep we're nested. this will tell us when to return
266 int _iLevels =0;
267
268 TokenBlock *block = 0;
269 while ((block = tokenizer.next())) {
270
271 // if we hit an end, return
272 if (block->tag == ConfigOpts::end) {
273 --_iLevels;
274 _keybindings->retract();
275 // 0 is our root level, so if we're below that, we need to bail out
276 if (_iLevels <0) {
277 if (block) delete block;
278 return;
279 }
280 } else {
281
282 string fullKey = block->name;
283
284 if (fullKey.size() <=0) {
285 cerr << BBTOOL << ": " << "ERROR: No key or modifier given. Ignoring this one, Jimmy.\n";
286 if (block) delete block;
287 continue;
288 }
289 // first, split our string containing our keys/modifiers and separate
290 // the keys from the modifiers
291 vector<string> results;
292 int matches = LocalUtil::splitString(fullKey, "-", results);
293
294 // here's our keyname. make sure it's a valid key
295 string _key = results[results.size() -1];
296
297 KeySym sym = XStringToKeysym(_key.c_str());
298 if (sym == 0) {
299 cerr << BBTOOL << ": " << "ERROR: Invalid key (" << _key << ")! This may cause odd behavior.\n";
300 }
301
302 // now iterate through our modifiers and try to match the given string
303 // to a modifier mask. if we find it, xor it together with what we already have
304 unsigned int _mask=0;
305
306 for (int j=0; j < (matches -1); j++) {
307
308 bool found=false;
309 string mod = results[j];
310
311 for (int i = 0; modifiers[i].str[0] != '\0'; ++i) {
312 if ( strcasecmp(modifiers[i].str, mod.c_str()) == 0 ) {
313 _mask |= modifiers[i].mask;
314 found = true;
315 break;
316 }
317 }
318 if (!found) cerr << BBTOOL << ": " << "ERROR: Couldn't find modifier for mod: [" << mod << "]\n";
319 }
320
321 // now, if we have a chain, nest down a level and add the keybinding
322 if (block->tag == Action::chain) {
323 _iLevels++;
324 _keybindings->advanceOnNewNode();
325 _keybindings->setCurrentNodeProps(static_cast<Action::ActionType>(block->tag),
326 _mask, _key, block->data);
327 } else {
328 _keybindings->addAction(static_cast<Action::ActionType>(block->tag),
329 _mask, _key, block->data);
330 }
331 }
332 if (block) delete block;
333 }
334 }
335
336 void KeyClient::initKeywords(KeywordMap& keywords) {
337
338 // load our map with our keybinding labels
339 keywords.insert(KeywordMap::value_type("execute", Action::execute));
340 keywords.insert(KeywordMap::value_type("iconify", Action::iconify));
341 keywords.insert(KeywordMap::value_type("raise", Action::raise));
342 keywords.insert(KeywordMap::value_type("lower", Action::lower));
343 keywords.insert(KeywordMap::value_type("close", Action::close));
344 keywords.insert(KeywordMap::value_type("toggleshade", Action::toggleShade));
345 keywords.insert(KeywordMap::value_type("toggleomnipresent", Action::toggleOmnipresent));
346 keywords.insert(KeywordMap::value_type("movewindowup", Action::moveWindowUp));
347 keywords.insert(KeywordMap::value_type("movewindowdown", Action::moveWindowDown));
348 keywords.insert(KeywordMap::value_type("movewindowleft", Action::moveWindowLeft));
349 keywords.insert(KeywordMap::value_type("movewindowright", Action::moveWindowRight));
350 keywords.insert(KeywordMap::value_type("resizewindowwidth", Action::resizeWindowWidth));
351 keywords.insert(KeywordMap::value_type("resizewindowheight", Action::resizeWindowHeight));
352
353 keywords.insert(KeywordMap::value_type("togglemaximizefull", Action::toggleMaximizeFull));
354 keywords.insert(KeywordMap::value_type("togglemaximizevertical", Action::toggleMaximizeVertical));
355 keywords.insert(KeywordMap::value_type("togglemaximizehorizontal", Action::toggleMaximizeHorizontal));
356
357 keywords.insert(KeywordMap::value_type("sendtoworkspace", Action::sendToWorkspace));
358 keywords.insert(KeywordMap::value_type("sendtonextworkspace", Action::sendToNextWorkspace));
359 keywords.insert(KeywordMap::value_type("sendtoprevworkspace", Action::sendToPrevWorkspace));
360
361 keywords.insert(KeywordMap::value_type("nextwindow", Action::nextWindow));
362 keywords.insert(KeywordMap::value_type("prevwindow", Action::prevWindow));
363 keywords.insert(KeywordMap::value_type("nextwindowonallworkspaces", Action::nextWindowOnAllWorkspaces));
364 keywords.insert(KeywordMap::value_type("prevwindowonallworkspaces", Action::prevWindowOnAllWorkspaces));
365
366 keywords.insert(KeywordMap::value_type("changeworkspace", Action::changeWorkspace));
367 keywords.insert(KeywordMap::value_type("nextworkspace", Action::nextWorkspace));
368 keywords.insert(KeywordMap::value_type("prevworkspace", Action::prevWorkspace));
369
370 keywords.insert(KeywordMap::value_type("upworkspace", Action::upWorkspace));
371 keywords.insert(KeywordMap::value_type("downworkspace", Action::downWorkspace));
372 keywords.insert(KeywordMap::value_type("leftworkspace", Action::leftWorkspace));
373 keywords.insert(KeywordMap::value_type("rightworkspace", Action::rightWorkspace));
374
375 keywords.insert(KeywordMap::value_type("nextscreen", Action::nextScreen));
376 keywords.insert(KeywordMap::value_type("prevscreen", Action::prevScreen));
377
378 keywords.insert(KeywordMap::value_type("showrootmenu", Action::showRootMenu));
379 keywords.insert(KeywordMap::value_type("showworkspacemenu", Action::showWorkspaceMenu));
380 keywords.insert(KeywordMap::value_type("toggledecorations", Action::toggleDecorations));
381
382 keywords.insert(KeywordMap::value_type("togglegrabs", Action::toggleGrabs));
383 keywords.insert(KeywordMap::value_type("chain", Action::chain));
384
385 // the words associated with our high-level file labels
386 keywords.insert(KeywordMap::value_type("begin", ConfigOpts::begin));
387 keywords.insert(KeywordMap::value_type("end", ConfigOpts::end));
388 keywords.insert(KeywordMap::value_type("config", ConfigOpts::config));
389 keywords.insert(KeywordMap::value_type("keybindings", ConfigOpts::keybindings));
390 keywords.insert(KeywordMap::value_type("option", ConfigOpts::option));
391
392 }
393
394 bool KeyClient::process_signal(int sig) {
395 switch (sig) {
396 case SIGHUP:
397 reconfigure();
398 return true;
399 break;
400
401 default:
402 return (bt::Application::process_signal(sig) );
403 }
404
405 }
406
407 void KeyClient::process_event(XEvent *e) {
408 // Send the event through the default EventHandlers.
409 bt::Application::process_event(e);
410 }
411
412 void KeyClient::cycleScreen(int current, bool forward) const {
413 unsigned int i;
414 for (i = 0; i < screenList.size(); ++i)
415 if (screenList[i]->getScreenNumber() == current) {
416 current = i;
417 break;
418 }
419 assert(i < screenList.size()); // current is for an unmanaged screen
420
421 int dest = current + (forward ? 1 : -1);
422
423 if (dest < 0) dest = (signed)screenList.size() - 1;
424 else if (dest >= (signed)screenList.size()) dest = 0;
425
426 const XWindow *target = screenList[dest]->lastActiveWindow();
427 if (target) target->focus();
428 }
429
430 void KeyClient::timeout(bt::Timer *timer) {
431 if (timer == config_check_timer) {
432 checkConfigFile();
433 }
434 }
435
436 void KeyClient::checkConfigFile() {
437
438 struct stat file_status;
439
440 if (stat(_configFileName.c_str(), &file_status) != 0) {
441 if (_debug)
442 std::cerr << BBTOOL << ": " << "Could not open config file: [" << _configFileName << "]";
443 } else if (file_status.st_mtime != _last_time_config_changed) {
444 if (_debug)
445 std::cout << BBTOOL << ": " << "KeyClient: checkConfigFile: config file time changed..." << std::endl;
446 _last_time_config_changed = file_status.st_mtime;
447 reconfigure();
448 }
449 }
450