1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.hh 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 #ifndef   __Window_hh
26 #define   __Window_hh
27 
28 #include "BlackboxResource.hh"
29 #include "Screen.hh"
30 
31 #include <EWMH.hh>
32 
33 
34 enum WindowType {
35   WindowTypeNormal,
36   WindowTypeDialog,
37   WindowTypeDesktop,
38   WindowTypeDock,
39   WindowTypeMenu,
40   WindowTypeSplash,
41   WindowTypeToolbar,
42   WindowTypeUtility
43 };
44 
45 enum WindowFunction {
46   WindowFunctionResize          = 1<<0,
47   WindowFunctionMove            = 1<<1,
48   WindowFunctionShade           = 1<<2,
49   WindowFunctionIconify         = 1<<3,
50   WindowFunctionMaximize        = 1<<4,
51   WindowFunctionClose           = 1<<5,
52   WindowFunctionChangeWorkspace = 1<<6,
53   WindowFunctionChangeLayer     = 1<<7,
54   WindowFunctionFullScreen      = 1<<8,
55   NoWindowFunctions             = 0,
56   AllWindowFunctions            = (WindowFunctionResize |
57                                    WindowFunctionMove |
58                                    WindowFunctionShade |
59                                    WindowFunctionIconify |
60                                    WindowFunctionMaximize |
61                                    WindowFunctionClose |
62                                    WindowFunctionChangeWorkspace |
63                                    WindowFunctionChangeLayer |
64                                    WindowFunctionFullScreen)
65 };
66 typedef unsigned short WindowFunctionFlags;
67 
68 enum WindowDecoration {
69   WindowDecorationTitlebar = 1<<0,
70   WindowDecorationHandle   = 1<<1,
71   WindowDecorationGrip     = 1<<2,
72   WindowDecorationBorder   = 1<<3,
73   WindowDecorationIconify  = 1<<4,
74   WindowDecorationMaximize = 1<<5,
75   WindowDecorationClose    = 1<<6,
76   NoWindowDecorations      = 0,
77   AllWindowDecorations     = (WindowDecorationTitlebar |
78                               WindowDecorationHandle |
79                               WindowDecorationGrip |
80                               WindowDecorationBorder |
81                               WindowDecorationIconify |
82                               WindowDecorationMaximize |
83                               WindowDecorationClose)
84 };
85 typedef unsigned char WindowDecorationFlags;
86 
87 struct EWMH {
88   WindowType window_type;
89   unsigned int workspace;
90   unsigned int modal        : 1;
91   unsigned int maxv         : 1;
92   unsigned int maxh         : 1;
93   unsigned int shaded       : 1;
94   unsigned int skip_taskbar : 1;
95   unsigned int skip_pager   : 1;
96   unsigned int hidden       : 1;
97   unsigned int fullscreen   : 1;
98   unsigned int above        : 1;
99   unsigned int below        : 1;
100 };
101 struct MotifHints {
102   WindowDecorationFlags decorations;
103   WindowFunctionFlags functions;
104 };
105 struct WMHints {
106   bool accept_focus;
107   Window window_group;
108   unsigned long initial_state;
109 };
110 struct WMNormalHints {
111   long flags;
112   unsigned int min_width, min_height;
113   unsigned int max_width, max_height;
114   unsigned int width_inc, height_inc;
115   unsigned int min_aspect_x, min_aspect_y;
116   unsigned int max_aspect_x, max_aspect_y;
117   unsigned int base_width, base_height;
118   unsigned int win_gravity;
119 };
120 struct WMProtocols {
121   unsigned int wm_delete_window : 1;
122   unsigned int wm_take_focus    : 1;
123 };
124 
125 
126 class BlackboxWindow : public StackEntity, public bt::TimeoutHandler,
127                        public bt::EventHandler, public bt::NoCopy {
128   Blackbox *blackbox;
129   BScreen *_screen;
130   bt::Timer *timer;
131 
132   Time lastButtonPressTime;  // used for double clicks, when were we clicked
133 
134   unsigned int window_number;
135 
136   struct ClientState {
137     unsigned int visible  : 1; // is visible?
138     unsigned int iconic   : 1; // is iconified?
139     unsigned int moving   : 1; // is moving?
140     unsigned int resizing : 1; // is resizing?
141     unsigned int focused  : 1; // has focus?
142     unsigned int shaped   : 1; // does the frame use the shape extension?
143   };
144 
145   struct _client {
146     Window window;                    // the client's window
147     Colormap colormap;
148     Window transient_for;             // which window are we a transient for?
149     BlackboxWindowList transientList; // which windows are our transients?
150 
151     bt::ustring title, visible_title, icon_title;
152 
153     bt::Rect rect, premax;
154 
155     int old_bw;                     // client's borderwidth
156 
157     unsigned long current_state;
158 
159     bt::EWMH::Strut *strut;
160 
161     WindowFunctionFlags functions;
162     WindowDecorationFlags decorations;
163 
164     ClientState state;
165 
166     EWMH ewmh;
167     MotifHints motif;
168     WMHints wmhints;
169     WMNormalHints wmnormal;
170     WMProtocols wmprotocols;
171   } client;
172 
173   /*
174    * client window = the application's window
175    * frame window = the window drawn around the outside of the client window
176    *                by the window manager which contains items like the
177    *                titlebar and close button
178    * title = the titlebar drawn above the client window, it displays the
179    *         window's name and any buttons for interacting with the window,
180    *         such as iconify, maximize, and close
181    * label = the window in the titlebar where the title is drawn
182    * buttons = maximize, iconify, close
183    * handle = the bar drawn at the bottom of the window, which contains the
184    *          left and right grips used for resizing the window
185    * grips = the smaller reactangles in the handle, one of each side of it.
186    *         When clicked and dragged, these resize the window interactively
187    * border = the line drawn around the outside edge of the frame window,
188    *          between the title, the bordered client window, and the handle.
189    *          Also drawn between the grips and the handle
190    */
191 
192   struct _frame {
193     // u -> unfocused, f -> has focus
194     Pixmap ulabel, flabel, utitle, ftitle, uhandle, fhandle,
195       ubutton, fbutton, pbutton, ugrip, fgrip;
196 
197     Window window,       // the frame
198       plate,             // holds the client
199       title,
200       label,
201       handle,
202       close_button, iconify_button, maximize_button,
203       right_grip, left_grip;
204 
205     // frame geometry
206     bt::Rect rect;
207 
208     // used during move/resize
209     bt::Rect changing;
210     int corner;
211 
212     /*
213      * margins between the frame and client, this has nothing to do
214      * with EWMH, it is simply code reuse for similar functionality
215      */
216     bt::EWMH::Strut margin;
217     int grab_x, grab_y;         // where was the window when it was grabbed?
218 
219     unsigned int label_w;       // width of the label
220   } frame;
221 
222   Window createToplevelWindow();
223   Window createChildWindow(Window parent, unsigned long event_mask,
224                            Cursor = None);
225 
226   void associateClientWindow(void);
227 
228   void decorate(void);
229 
230   void positionButtons(bool redecorate_label = false);
231   void positionWindows(void);
232 
233   void createTitlebar(void);
234   void destroyTitlebar(void);
235   void createHandle(void);
236   void destroyHandle(void);
237   void createGrips(void);
238   void destroyGrips(void);
239   void createIconifyButton(void);
240   void destroyIconifyButton(void);
241   void createMaximizeButton(void);
242   void destroyMaximizeButton(void);
243   void createCloseButton(void);
244   void destroyCloseButton(void);
245 
246   void redrawWindowFrame(void) const;
247   void redrawTitle(void) const;
248   void redrawLabel(void) const;
249   void redrawAllButtons(void) const;
250   void redrawCloseButton(bool pressed = false) const;
251   void redrawIconifyButton(bool pressed = false) const;
252   void redrawMaximizeButton(bool pressed = false) const;
253   void redrawHandle(void) const;
254   void redrawGrips(void) const;
255 
256   void setState(unsigned long new_state);
257   void updateEWMHState();
258   void updateEWMHAllowedActions();
259 
260   void startMove();
261   void snapAdjust(int *x, int *y);
262   void continueMove(int x_root, int y_root);
263   void finishMove();
264 
265   void startResize(Window window);
266   void continueResize(int x_root, int y_root);
267   void finishResize();
268 
269   void showGeometry(const bt::Rect &r) const;
270 
271 public:
272   BlackboxWindow(Blackbox *b, Window w, BScreen *s);
273   virtual ~BlackboxWindow(void);
274 
isTransient(void) const275   inline bool isTransient(void) const
276   { return client.transient_for != 0; }
isGroupTransient(void) const277   inline bool isGroupTransient(void) const
278   { return (client.transient_for != 0
279             && client.transient_for == client.wmhints.window_group); }
isModal(void) const280   inline bool isModal(void) const
281   { return client.ewmh.modal; }
282 
windowType(void) const283   inline WindowType windowType(void) const
284   { return client.ewmh.window_type; }
285 
hasWindowFunction(WindowFunction function) const286   inline bool hasWindowFunction(WindowFunction function) const
287   { return client.functions & function; }
hasWindowDecoration(WindowDecoration decoration) const288   inline bool hasWindowDecoration(WindowDecoration decoration) const
289   { return client.decorations & decoration; }
290 
291   // ordered newest to oldest
transients(void) const292   inline const BlackboxWindowList &transients(void) const
293   { return client.transientList; }
294 
295   void addTransient(BlackboxWindow *win);
296   void removeTransient(BlackboxWindow *win);
297 
298   BlackboxWindow *findTransientFor(void) const;
299   BlackboxWindow *findNonTransientParent(void) const;
300   BlackboxWindowList buildFullTransientList(void) const;
301 
302   BWindowGroup *findWindowGroup(void) const;
303 
screen(void) const304   inline BScreen *screen(void) const
305   { return _screen; }
306 
307   // StackEntity interface
windowID(void) const308   inline Window windowID(void) const
309   { return frame.window; }
310 
frameWindow(void) const311   inline Window frameWindow(void) const
312   { return frame.window; }
clientWindow(void) const313   inline Window clientWindow(void) const
314   { return client.window; }
315 
title(void) const316   inline const bt::ustring &title(void) const
317   { return client.title; }
iconTitle(void) const318   inline const bt::ustring &iconTitle(void) const
319   { return client.icon_title.empty() ? client.title : client.icon_title; }
320 
workspace(void) const321   inline unsigned int workspace(void) const
322   { return client.ewmh.workspace; }
323   void setWorkspace(unsigned int new_workspace);
324 
325   enum ChangeWorkspaceOption {
326     StayOnCurrentWorkspace,
327     SwitchToNewWorkspace
328   };
329   void changeWorkspace(unsigned int new_workspace,
330                        ChangeWorkspaceOption how = StayOnCurrentWorkspace);
331 
332   void changeLayer(StackingList::Layer new_layer);
333 
windowNumber(void) const334   inline unsigned int windowNumber(void) const
335   { return window_number; }
setWindowNumber(int n)336   inline void setWindowNumber(int n)
337   { window_number = n; }
338 
frameRect(void) const339   inline const bt::Rect &frameRect(void) const
340   { return frame.rect; }
clientRect(void) const341   inline const bt::Rect &clientRect(void) const
342   { return client.rect; }
343 
wmHints(void) const344   const WMHints &wmHints(void) const
345   { return client.wmhints; }
wmNormalHints(void) const346   const WMNormalHints &wmNormalHints(void) const
347   { return client.wmnormal; }
wmProtocols(void) const348   const WMProtocols &wmProtocols(void) const
349   { return client.wmprotocols; }
350 
currentState(void) const351   unsigned long currentState(void) const
352   { return client.current_state; }
353 
isFocused(void) const354   inline bool isFocused(void) const
355   { return client.state.focused; }
356   void setFocused(bool focused);
357   bool setInputFocus(void);
358 
isVisible(void) const359   inline bool isVisible(void) const
360   { return client.state.visible; }
361   void show(void);
362   void hide(void);
363   void close(void);
364   void activate(void);
365 
isShaded(void) const366   inline bool isShaded(void) const
367   { return client.ewmh.shaded; }
368   void setShaded(bool shaded);
369 
isIconic(void) const370   inline bool isIconic(void) const
371   { return client.state.iconic; }
372   void iconify(void); // call show() to deiconify
373 
isMaximized(void) const374   inline bool isMaximized(void) const
375   { return client.ewmh.maxh || client.ewmh.maxv; }
376   // ### change to setMaximized()?
377   void maximize(unsigned int button);
378   void remaximize(void);
379 
isFullScreen(void) const380   inline bool isFullScreen(void) const
381   { return client.ewmh.fullscreen; }
382   void setFullScreen(bool b);
383 
384   void reconfigure(void);
385   void grabButtons(void);
386   void ungrabButtons(void);
387   void restore(void);
388   void configure(int dx, int dy, unsigned int dw, unsigned int dh);
configure(const bt::Rect & r)389   inline void configure(const bt::Rect &r)
390   { configure(r.x(), r.y(), r.width(), r.height()); }
391 
392   void clientMessageEvent(const XClientMessageEvent * const ce);
393   void buttonPressEvent(const XButtonEvent * const be);
394   void buttonReleaseEvent(const XButtonEvent * const re);
395   void motionNotifyEvent(const XMotionEvent * const me);
396   void destroyNotifyEvent(const XDestroyWindowEvent * const /*unused*/);
397   void unmapNotifyEvent(const XUnmapEvent * const /*unused*/);
398   void reparentNotifyEvent(const XReparentEvent * const /*unused*/);
399   void propertyNotifyEvent(const XPropertyEvent * const pe);
400   void exposeEvent(const XExposeEvent * const ee);
401   void configureRequestEvent(const XConfigureRequestEvent * const cr);
402   void enterNotifyEvent(const XCrossingEvent * const ce);
403   void leaveNotifyEvent(const XCrossingEvent * const /*unused*/);
404 
405 #ifdef SHAPE
406   void configureShape(void);
407   void shapeEvent(const XEvent * const /*unused*/);
408 #endif // SHAPE
409 
410   virtual void timeout(bt::Timer *);
411 };
412 
413 #endif // __Window_hh
414