1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // BlackboxResource.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 //         Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24 
25 #include "BlackboxResource.hh"
26 
27 #include "blackbox.hh"
28 
29 #include <cstring>
30 #include <Image.hh>
31 #include <Resource.hh>
32 
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/cursorfont.h>
36 
37 
BlackboxResource(const std::string & rc)38 BlackboxResource::BlackboxResource(const std::string& rc): rc_file(rc) {
39   screen_resources = 0;
40   auto_raise_delay.tv_sec = auto_raise_delay.tv_usec = 0;
41 }
42 
43 
~BlackboxResource(void)44 BlackboxResource::~BlackboxResource(void)
45 { delete [] screen_resources; }
46 
47 
load(Blackbox & blackbox)48 void BlackboxResource::load(Blackbox& blackbox) {
49   if (screen_resources == 0) {
50     screen_resources = new ScreenResource[blackbox.screenCount()];
51   }
52 
53   bt::Resource res(rc_file);
54 
55   menu_file = bt::expandTilde(res.read("session.menuFile",
56                                        "Session.MenuFile",
57                                        DEFAULTMENU));
58 
59   style_file = bt::expandTilde(res.read("session.styleFile",
60                                         "Session.StyleFile",
61                                         DEFAULTSTYLE));
62 
63   unsigned int maxcolors = res.read("session.maximumColors",
64                                     "Session.MaximumColors",
65                                     ~0u);
66   if (maxcolors != ~0u)
67     bt::Image::setMaximumColors(maxcolors);
68 
69   double_click_interval = res.read("session.doubleClickInterval",
70                                    "Session.DoubleClickInterval",
71                                    250l);
72 
73   auto_raise_delay.tv_usec = res.read("session.autoRaiseDelay",
74                                       "Session.AutoRaiseDelay",
75                                       400l);
76 
77   auto_raise_delay.tv_sec = auto_raise_delay.tv_usec / 1000;
78   auto_raise_delay.tv_usec -= (auto_raise_delay.tv_sec * 1000);
79   auto_raise_delay.tv_usec *= 1000;
80 
81   bt::DitherMode dither_mode;
82   std::string str = res.read("session.imageDither",
83                              "Session.ImageDither",
84                              "OrderedDither");
85   if (!strcasecmp("ordered", str.c_str()) ||
86       !strcasecmp("fast", str.c_str()) ||
87       !strcasecmp("ordereddither", str.c_str()) ||
88       !strcasecmp("fastdither", str.c_str())) {
89     dither_mode = bt::OrderedDither;
90   } else if (!strcasecmp("floydsteinberg", str.c_str()) ||
91              !strcasecmp("quality", str.c_str()) ||
92              !strcasecmp("diffuse", str.c_str()) ||
93              !strcasecmp("floydsteinbergdither", str.c_str()) ||
94              !strcasecmp("qualitydither", str.c_str()) ||
95              !strcasecmp("diffusedither", str.c_str())) {
96     dither_mode = bt::FloydSteinbergDither;
97   } else if (!strcasecmp("no", str.c_str()) ||
98              !strcasecmp("nodither", str.c_str()) ||
99              !strcasecmp("off", str.c_str())) {
100     dither_mode = bt::NoDither;
101   } else {
102     dither_mode = bt::OrderedDither;
103   }
104   bt::Image::setDitherMode(dither_mode);
105 
106   _cursors.pointer =
107     XCreateFontCursor(blackbox.XDisplay(), XC_left_ptr);
108   _cursors.move =
109     XCreateFontCursor(blackbox.XDisplay(), XC_fleur);
110   _cursors.resize_top_left =
111     XCreateFontCursor(blackbox.XDisplay(), XC_top_left_corner);
112   _cursors.resize_bottom_left =
113     XCreateFontCursor(blackbox.XDisplay(), XC_bottom_left_corner);
114   _cursors.resize_top_right =
115     XCreateFontCursor(blackbox.XDisplay(), XC_top_right_corner);
116   _cursors.resize_bottom_right =
117     XCreateFontCursor(blackbox.XDisplay(), XC_bottom_right_corner);
118 
119   // window options
120   str = res.read("session.focusModel",
121                  "Session.FocusModel",
122                  res.read("session.screen0.focusModel",
123                           "Session.Screen0.FocusModel",
124                           "ClickToFocus"));
125   if (str.find("ClickToFocus") != std::string::npos) {
126     focus_model = ClickToFocusModel;
127     auto_raise = false;
128     click_raise = false;
129   } else {
130     focus_model = SloppyFocusModel;
131     auto_raise = (str.find("AutoRaise") != std::string::npos);
132     click_raise = (str.find("ClickRaise") != std::string::npos);
133   }
134 
135   str = res.read("session.windowPlacement",
136                  "Session.WindowPlacement",
137                  res.read("session.screen0.windowPlacement",
138                           "Session.Screen0.WindowPlacement",
139                           "RowSmartPlacement"));
140   if (strcasecmp(str.c_str(), "ColSmartPlacement") == 0)
141     window_placement_policy = ColSmartPlacement;
142   else if (strcasecmp(str.c_str(), "CenterPlacement") == 0)
143     window_placement_policy = CenterPlacement;
144   else if (strcasecmp(str.c_str(), "CascadePlacement") == 0)
145     window_placement_policy = CascadePlacement;
146   else
147     window_placement_policy = RowSmartPlacement;
148 
149   str = res.read("session.rowPlacementDirection",
150                  "Session.RowPlacementDirection",
151                  res.read("session.screen0.rowPlacementDirection",
152                           "Session.Screen0.RowPlacementDirection",
153                           "lefttoright"));
154   row_direction =
155     (strcasecmp(str.c_str(), "righttoleft") == 0) ? RightLeft : LeftRight;
156 
157   str = res.read("session.colPlacementDirection",
158                  "Session.ColPlacementDirection",
159                  res.read("session.screen0.colPlacementDirection",
160                           "Session.Screen0.ColPlacementDirection",
161                           "toptobottom"));
162   col_direction =
163     (strcasecmp(str.c_str(), "bottomtotop") == 0) ? BottomTop : TopBottom;
164 
165   ignore_shaded =
166     res.read("session.placementIgnoresShaded",
167              "Session.placementIgnoresShaded",
168              true);
169 
170   opaque_move =
171     res.read("session.opaqueMove",
172              "Session.OpaqueMove",
173              true);
174   opaque_resize =
175     res.read("session.opaqueResize",
176              "Session.OpaqueResize",
177              true);
178   full_max =
179     res.read("session.fullMaximization",
180              "Session.FullMaximization",
181              res.read("session.screen0.fullMaximization",
182                       "Session.Screen0.FullMaximization",
183                       false));
184   focus_new_windows =
185     res.read("session.focusNewWindows",
186              "Session.FocusNewWindows",
187              res.read("session.screen0.focusNewWindows",
188                       "Session.Screen0.FocusNewWindows",
189                       true));
190   focus_last_window_on_workspace =
191     res.read("session.focusLastWindow",
192              "Session.focusLastWindow",
193              res.read("session.screen0.focusLastWindow",
194                       "Session.Screen0.focusLastWindow",
195                       true));
196   change_workspace_with_mouse_wheel =
197     res.read("session.changeWorkspaceWithMouseWheel",
198              "session.changeWorkspaceWithMouseWheel",
199              true);
200   shade_window_with_mouse_wheel =
201     res.read("session.shadeWindowWithMouseWheel",
202              "session.shadeWindowWithMouseWheel",
203              true);
204   toolbar_actions_with_mouse_wheel =
205     res.read("session.toolbarActionsWithMouseWheel",
206              "session.toolbarActionsWithMouseWheel",
207              true);
208   allow_scroll_lock =
209     res.read("session.disableBindingsWithScrollLock",
210              "Session.disableBindingsWithScrollLock",
211              res.read("session.screen0.disableBindingsWithScrollLock",
212                       "Session.Screen0.disableBindingsWithScrollLock",
213                       false));
214   edge_snap_threshold =
215     res.read("session.edgeSnapThreshold",
216              "Session.EdgeSnapThreshold",
217              res.read("session.screen0.edgeSnapThreshold",
218                       "Session.Screen0.EdgeSnapThreshold",
219                       0));
220   window_snap_threshold =
221     res.read("session.windowSnapThreshold",
222              "Session.windowSnapThreshold",
223              0);
224 
225   for (unsigned int i = 0; i < blackbox.screenCount(); ++i)
226     screen_resources[i].load(res, i);
227 }
228 
229 
save(Blackbox & blackbox)230 void BlackboxResource::save(Blackbox& blackbox) {
231   bt::Resource res;
232 
233   {
234     if (bt::Resource(rc_file).read("session.cacheLife",
235                                    "Session.CacheLife",
236                                    -1) == -1) {
237       res.merge(rc_file);
238     } else {
239       // we are converting from 0.65.0 to 0.70.0, let's take the liberty
240       // of generating a brand new rc file to make sure we throw out
241       // undeeded entries
242     }
243   }
244 
245   res.write("session.menuFile", menuFilename());
246 
247   res.write("session.styleFile", styleFilename());
248 
249   res.write("session.maximumColors",  bt::Image::maximumColors());
250 
251   res.write("session.doubleClickInterval", double_click_interval);
252 
253   res.write("session.autoRaiseDelay", ((auto_raise_delay.tv_sec * 1000ul) +
254                                        (auto_raise_delay.tv_usec / 1000ul)));
255 
256   std::string str;
257   switch (bt::Image::ditherMode()) {
258   case bt::OrderedDither:        str = "OrderedDither";        break;
259   case bt::FloydSteinbergDither: str = "FloydSteinbergDither"; break;
260   default:                       str = "NoDither";             break;
261   }
262   res.write("session.imageDither", str);
263 
264   // window options
265   switch (focus_model) {
266   case SloppyFocusModel:
267   default:
268     str = "SloppyFocus";
269     if (auto_raise)
270       str += " AutoRaise";
271     if (click_raise)
272       str += " ClickRaise";
273     break;
274   case ClickToFocusModel:
275     str = "ClickToFocus";
276     break;
277   }
278   res.write("session.focusModel", str);
279 
280   switch (window_placement_policy) {
281   case CascadePlacement:
282     str = "CascadePlacement";
283     break;
284   case CenterPlacement:
285     str = "CenterPlacement";
286     break;
287   case ColSmartPlacement:
288     str = "ColSmartPlacement";
289     break;
290   case RowSmartPlacement:
291   default:
292     str = "RowSmartPlacement";
293     break;
294   }
295   res.write("session.windowPlacement", str);
296   res.write("session.rowPlacementDirection",
297             (row_direction == LeftRight)
298             ? "LeftToRight"
299             : "RightToLeft");
300   res.write("session.colPlacementDirection",
301             (col_direction == TopBottom)
302             ? "TopToBottom"
303             : "BottomToTop");
304 
305   res.write("session.placementIgnoresShaded", ignore_shaded);
306 
307   res.write("session.opaqueMove", opaque_move);
308   res.write("session.opaqueResize", opaque_resize);
309   res.write("session.fullMaximization", full_max);
310   res.write("session.focusNewWindows", focus_new_windows);
311   res.write("session.focusLastWindow", focus_last_window_on_workspace);
312   res.write("session.changeWorkspaceWithMouseWheel",
313             change_workspace_with_mouse_wheel);
314   res.write("session.shadeWindowWithMouseWheel",
315             shade_window_with_mouse_wheel);
316   res.write("session.toolbarActionsWithMouseWheel",
317             toolbar_actions_with_mouse_wheel);
318   res.write("session.disableBindingsWithScrollLock", allow_scroll_lock);
319   res.write("session.edgeSnapThreshold", edge_snap_threshold);
320   res.write("session.windowSnapThreshold", window_snap_threshold);
321 
322   for (unsigned int i = 0; i < blackbox.screenCount(); ++i)
323     screen_resources[i].save(res, blackbox.screenNumber(i));
324 
325   res.save(rc_file);
326 }
327 
328 
329