]> icculus.org git repositories - mikachu/openbox.git/blob - src/frame.cc
support for the shape extension works!
[mikachu/openbox.git] / src / frame.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef    SHAPE
9 #include <X11/extensions/shape.h>
10 #endif // SHAPE
11 }
12
13 #include "frame.hh"
14 #include "client.hh"
15 #include "otk/display.hh"
16
17 namespace ob {
18
19 OBFrame::OBFrame(const OBClient *client, const otk::Style *style)
20   : _client(client),
21     _screen(otk::OBDisplay::screenInfo(client->screen()))
22 {
23   assert(client);
24   assert(style);
25   
26   _style = 0;
27   loadStyle(style);
28
29   _window = createFrame();
30   assert(_window);
31
32   grabClient();
33 }
34
35
36 OBFrame::~OBFrame()
37 {
38   releaseClient(false);
39 }
40
41
42 void OBFrame::loadStyle(const otk::Style *style)
43 {
44   assert(style);
45
46   // if a style was previously set, then 'replace' is true, cause we're
47   // replacing a style
48   // NOTE: if this is false, then DO NOT DO SHIT WITH _window, it doesnt exist
49   bool replace = (_style);
50
51   if (replace) {
52     // XXX: do shit here whatever
53   }
54   
55   _style = style;
56
57   // XXX: load shit like this from the style!
58   _size.left = _size.top = _size.bottom = _size.right = 2;
59
60   if (replace) {
61     resize();
62     
63     XSetWindowBorderWidth(otk::OBDisplay::display, _window,
64                           _style->getBorderWidth());
65
66     XMoveWindow(otk::OBDisplay::display, _client->window(),
67                 _size.left, _size.top);
68
69     // XXX: make everything redraw
70   }
71 }
72
73
74 void OBFrame::resize()
75 {
76   XResizeWindow(otk::OBDisplay::display, _window,
77                 _size.left + _size.right + _client->area().width(),
78                 _size.top + _size.bottom + _client->area().height());
79   // XXX: more is gunna have to happen here
80 }
81
82
83 void OBFrame::shape()
84 {
85 #ifdef SHAPE
86   if (!_client->shaped()) {
87     // clear the shape on the frame window
88     XShapeCombineMask(otk::OBDisplay::display, _window, ShapeBounding,
89                       _size.left - 2,//frame.margin.left - frame.border_w,
90                       _size.top - 2,//frame.margin.top - frame.border_w,
91                       None, ShapeSet);
92   } else {
93     // make the frame's shape match the clients
94     XShapeCombineShape(otk::OBDisplay::display, _window, ShapeBounding,
95                        _size.left - 2,
96                        _size.top - 2,
97                        _client->window(), ShapeBounding, ShapeSet);
98
99   int num = 0;
100     XRectangle xrect[2];
101
102     /*
103     if (decorations & Decor_Titlebar) {
104     xrect[0].x = xrect[0].y = -frame.border_w;
105     xrect[0].width = frame.rect.width();
106     xrect[0].height = frame.title_h + (frame.border_w * 2);
107     ++num;
108     }
109
110     if (decorations & Decor_Handle) {
111     xrect[1].x = -frame.border_w;
112     xrect[1].y = frame.rect.height() - frame.margin.bottom +
113     frame.mwm_border_w - frame.border_w;
114     xrect[1].width = frame.rect.width();
115     xrect[1].height = frame.handle_h + (frame.border_w * 2);
116     ++num;
117     }*/
118
119     XShapeCombineRectangles(otk::OBDisplay::display, _window,
120                             ShapeBounding, 0, 0, xrect, num,
121                             ShapeUnion, Unsorted);
122   }
123 #endif // SHAPE
124 }
125
126
127 void OBFrame::grabClient()
128 {
129   
130   XGrabServer(otk::OBDisplay::display);
131
132   // select the event mask on the frame
133   XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
134
135   // reparent the client to the frame
136   XSelectInput(otk::OBDisplay::display, _client->window(),
137                OBClient::event_mask & ~StructureNotifyMask);
138   XReparentWindow(otk::OBDisplay::display, _client->window(), _window,
139                   _size.left, _size.top);
140   XSelectInput(otk::OBDisplay::display, _client->window(),
141                OBClient::event_mask);
142
143   // raise the client above the frame
144   XRaiseWindow(otk::OBDisplay::display, _client->window());
145   // map the client so it maps when the frame does
146   XMapWindow(otk::OBDisplay::display, _client->window());
147   
148   XUngrabServer(otk::OBDisplay::display);
149
150   resize();
151   shape();
152 }
153
154
155 void OBFrame::releaseClient(bool remap)
156 {
157   // check if the app has already reparented its window to the root window
158   XEvent ev;
159   if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
160                              ReparentNotify, &ev)) {
161     remap = true; // XXX: why do we remap the window if they already
162                   // reparented to root?
163   } else {
164     // according to the ICCCM - if the client doesn't reparent to
165     // root, then we have to do it for them
166     XReparentWindow(otk::OBDisplay::display, _client->window(),
167                     _screen->getRootWindow(),
168                     _client->area().x(), _client->area().y());
169   }
170
171   // if we want to remap the window, do so now
172   if (remap)
173     XMapWindow(otk::OBDisplay::display, _client->window());
174 }
175
176
177 Window OBFrame::createFrame()
178 {
179   XSetWindowAttributes attrib_create;
180   unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
181                               CWOverrideRedirect | CWEventMask;
182
183   attrib_create.background_pixmap = None;
184   attrib_create.colormap = _screen->getColormap();
185   attrib_create.override_redirect = True;
186   attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
187   /*
188     We catch button presses because other wise they get passed down to the
189     root window, which will then cause root menus to show when you click the
190     window's frame.
191   */
192
193   return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
194                        0, 0, 1, 1, _style->getBorderWidth(),
195                        _screen->getDepth(), InputOutput, _screen->getVisual(),
196                        create_mask, &attrib_create);
197 }
198
199 }