1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Windowmenu.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 "Windowmenu.hh"
26 #include "Screen.hh"
27 #include "Window.hh"
28 #include "Workspace.hh"
29 
30 #include <Unicode.hh>
31 
32 #include <assert.h>
33 
34 // #define WITH_FULLSCREEN
35 
36 
37 class SendToWorkspacemenu : public bt::Menu {
38 public:
39   SendToWorkspacemenu(bt::Application &app, unsigned int screen);
40 
setWindow(BlackboxWindow * win)41   inline void setWindow(BlackboxWindow *win)
42   { _window = win; }
43 
44   void refresh(void);
45 
46 protected:
47   virtual void itemClicked(unsigned int id, unsigned int button);
48 
49 private:
50   BlackboxWindow *_window;
51 };
52 
53 
54 enum {
55   SendToWorkspace,
56   OccupyAllWorkspaces,
57   Shade,
58   Iconify,
59   Maximize,
60 #if defined(WITH_FULLSCREEN)
61   FullScreen,
62 #endif
63   AlwaysOnTop,
64   AlwaysOnBottom,
65   KillClient,
66   Close
67 };
68 
Windowmenu(bt::Application & app,unsigned int screen)69 Windowmenu::Windowmenu(bt::Application &app, unsigned int screen)
70   : bt::Menu(app, screen), _window(0)
71 {
72   _sendto = new SendToWorkspacemenu(app, screen);
73   insertItem(bt::toUnicode("Send to Workspace"), _sendto, SendToWorkspace);
74   insertItem(bt::toUnicode("Occupy all Workspaces"), OccupyAllWorkspaces);
75   insertSeparator();
76   insertItem(bt::toUnicode("Shade"), Shade);
77   insertItem(bt::toUnicode("Iconify"), Iconify);
78   insertItem(bt::toUnicode("Maximize"), Maximize);
79 #if defined(WITH_FULLSCREEN)
80   insertItem(bt::toUnicode("Full Screen"), FullScreen);
81 #endif
82   insertItem(bt::toUnicode("Always on top"), AlwaysOnTop);
83   insertItem(bt::toUnicode("Always on bottom"), AlwaysOnBottom);
84   insertSeparator();
85   insertItem(bt::toUnicode("Kill Client"), KillClient);
86   insertItem(bt::toUnicode("Close"), Close);
87 }
88 
89 
setWindow(BlackboxWindow * win)90 void Windowmenu::setWindow(BlackboxWindow *win) {
91   _window = win;
92   _sendto->setWindow(win);
93 }
94 
95 
hide(void)96 void Windowmenu::hide(void) {
97   bt::Menu::hide();
98   setWindow(0);
99 }
100 
101 
refresh(void)102 void Windowmenu::refresh(void) {
103   assert(_window != 0);
104 
105   setItemEnabled(SendToWorkspace,
106                  _window->hasWindowFunction(WindowFunctionChangeWorkspace)
107                  && _window->workspace() != bt::BSENTINEL);
108 
109   setItemEnabled(OccupyAllWorkspaces,
110                  _window->hasWindowFunction(WindowFunctionChangeWorkspace));
111   setItemChecked(OccupyAllWorkspaces,
112                  _window->workspace() == bt::BSENTINEL);
113 
114   setItemEnabled(Shade, _window->hasWindowFunction(WindowFunctionShade));
115   setItemChecked(Shade, _window->isShaded());
116 
117   setItemEnabled(Iconify, _window->hasWindowFunction(WindowFunctionIconify));
118   setItemChecked(Iconify, _window->isIconic());
119 
120   setItemEnabled(Maximize, _window->hasWindowFunction(WindowFunctionMaximize));
121   setItemChecked(Maximize, _window->isMaximized());
122 
123 #if defined(WITH_FULLSCREEN)
124   setItemEnabled(FullScreen, _window->windowType() == WindowTypeNormal);
125   setItemChecked(FullScreen, _window->isFullScreen());
126 #endif
127 
128   setItemEnabled(AlwaysOnTop,
129                  _window->hasWindowFunction(WindowFunctionChangeLayer));
130   setItemChecked(AlwaysOnTop,
131                  _window->layer() == StackingList::LayerAbove);
132 
133   setItemEnabled(AlwaysOnBottom,
134                  _window->hasWindowFunction(WindowFunctionChangeLayer));
135   setItemChecked(AlwaysOnBottom,
136                  _window->layer() == StackingList::LayerBelow);
137 
138   setItemEnabled(KillClient, !_window->isTransient());
139 
140   setItemEnabled(Close, _window->hasWindowFunction(WindowFunctionClose));
141 }
142 
143 
itemClicked(unsigned int id,unsigned int)144 void Windowmenu::itemClicked(unsigned int id, unsigned int) {
145   switch (id) {
146   case OccupyAllWorkspaces:
147     {
148       BScreen *screen = _window->screen();
149       unsigned int workspace = (_window->workspace() == bt::BSENTINEL
150                                 ? screen->currentWorkspace()
151                                 : bt::BSENTINEL);
152       _window->changeWorkspace(workspace);
153       break;
154     }
155 
156   case Shade:
157     _window->setShaded(!_window->isShaded());
158     break;
159 
160   case Iconify:
161     _window->iconify();
162     break;
163 
164   case Maximize:
165     _window->maximize(1);
166     break;
167 
168 #if defined(WITH_FULLSCREEN)
169   case FullScreen:
170     _window->setFullScreen(!_window->isFullScreen());
171     break;
172 #endif
173 
174   case AlwaysOnTop:
175     {
176       StackingList::Layer new_layer =
177         (_window->layer() == StackingList::LayerAbove
178          ? StackingList::LayerNormal
179          : StackingList::LayerAbove);
180       _window->changeLayer(new_layer);
181       break;
182     }
183 
184   case AlwaysOnBottom:
185     {
186       StackingList::Layer new_layer =
187         (_window->layer() == StackingList::LayerBelow
188          ? StackingList::LayerNormal
189          : StackingList::LayerBelow);
190       _window->changeLayer(new_layer);
191       break;
192     }
193 
194   case KillClient:
195     XKillClient(_window->screen()->screenInfo().display().XDisplay(),
196                 _window->clientWindow());
197     break;
198 
199   case Close:
200     _window->close();
201     break;
202   } // switch
203 }
204 
205 
SendToWorkspacemenu(bt::Application & app,unsigned int screen)206 SendToWorkspacemenu::SendToWorkspacemenu(bt::Application &app,
207                                          unsigned int screen)
208   : bt::Menu(app, screen), _window(0)
209 { }
210 
211 
refresh(void)212 void SendToWorkspacemenu::refresh(void) {
213   assert(_window != 0);
214 
215   clear();
216   BScreen *screen = _window->screen();
217   const unsigned num = screen->workspaceCount();
218   for (unsigned int i = 0; i < num; ++i)
219     insertItem(screen->resource().workspaceName(i), i);
220 
221   /*
222     give a little visual indication to the user about which workspace
223     the window is on.  you obviously can't send a window to the workspace
224     the window is already on, which is why it is checked and disabled
225   */
226   setItemEnabled(_window->workspace(), false);
227   setItemChecked(_window->workspace(), true);
228 }
229 
230 
itemClicked(unsigned int id,unsigned int button)231 void SendToWorkspacemenu::itemClicked(unsigned int id, unsigned int button) {
232   assert(_window != 0);
233   _window->changeWorkspace(id,
234                            (button == 2
235                             ? BlackboxWindow::SwitchToNewWorkspace
236                             : BlackboxWindow::StayOnCurrentWorkspace));
237 
238   if (button == 2) {
239     BScreen *screen = _window->screen();
240     screen->setCurrentWorkspace(_window->workspace());
241   }
242 }
243