]> Dogcows Code - chaz/openbox/blob - c/frame.c
merge the C branch into HEAD
[chaz/openbox] / c / frame.c
1 #include "openbox.h"
2 #include "frame.h"
3 #include "extensions.h"
4 #include "hooks.h"
5
6 #define PLATE_EVENTMASK (SubstructureRedirectMask | ButtonPressMask)
7 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask)
8
9 static Window createWindow(Window parent, unsigned long mask,
10 XSetWindowAttributes *attrib)
11 {
12 /* XXX DONT USE THE DEFAULT SHIT */
13 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
14 DefaultDepth(ob_display, ob_screen), InputOutput,
15 DefaultVisual(ob_display, ob_screen),
16 mask, attrib);
17
18 }
19
20 Frame *frame_new(Client *client)
21 {
22 XSetWindowAttributes attrib;
23 unsigned long mask;
24 Frame *self;
25
26 self = g_new(Frame, 1);
27
28 self->client = client;
29 self->visible = FALSE;
30
31 /* create all of the decor windows */
32 mask = CWOverrideRedirect | CWEventMask;
33 attrib.event_mask = FRAME_EVENTMASK;
34 attrib.override_redirect = TRUE;
35 self->window = createWindow(ob_root, mask, &attrib);
36
37 mask = 0;
38 self->plate = createWindow(self->window, mask, &attrib);
39 mask = CWEventMask;
40 attrib.event_mask = (ButtonPressMask | ButtonReleaseMask |
41 ButtonMotionMask | ExposureMask);
42 self->title = createWindow(self->window, mask, &attrib);
43 self->label = createWindow(self->title, mask, &attrib);
44 self->max = createWindow(self->title, mask, &attrib);
45 self->close = createWindow(self->title, mask, &attrib);
46 self->desk = createWindow(self->title, mask, &attrib);
47 self->icon = createWindow(self->title, mask, &attrib);
48 self->iconify = createWindow(self->title, mask, &attrib);
49 self->handle = createWindow(self->window, mask, &attrib);
50 mask |= CWCursor;
51 attrib.cursor = ob_cursors.ll_angle;
52 self->lgrip = createWindow(self->handle, mask, &attrib);
53 attrib.cursor = ob_cursors.lr_angle;
54 self->rgrip = createWindow(self->handle, mask, &attrib);
55
56 /* the other stuff is shown based on decor settings */
57 XMapWindow(ob_display, self->plate);
58 XMapWindow(ob_display, self->lgrip);
59 XMapWindow(ob_display, self->rgrip);
60 XMapWindow(ob_display, self->label);
61
62
63 /* XXX TEMPORARY OF COURSE!@&*(@! */
64
65 XSetWindowBackground(ob_display, self->title, 0x3333aa);
66 XSetWindowBackground(ob_display, self->handle, 0x3333aa);
67 XSetWindowBackground(ob_display, self->lgrip, 0x2233aa);
68 XSetWindowBackground(ob_display, self->rgrip, 0x2233aa);
69
70 XSetWindowBorder(ob_display, self->window, 0);
71 XSetWindowBorder(ob_display, self->label, 0);
72 XSetWindowBorder(ob_display, self->rgrip, 0);
73 XSetWindowBorder(ob_display, self->lgrip, 0);
74 XSetWindowBorder(ob_display, self->plate, 0x771122);
75
76 /* XXX /TEMPORARY OF COURSE!@&*(@! */
77
78 /* set all the windows for the frame in the client_map */
79 g_hash_table_insert(client_map, (gpointer)self->window, self->client);
80 g_hash_table_insert(client_map, (gpointer)self->plate, self->client);
81 g_hash_table_insert(client_map, (gpointer)self->title, self->client);
82 g_hash_table_insert(client_map, (gpointer)self->label, self->client);
83 g_hash_table_insert(client_map, (gpointer)self->max, self->client);
84 g_hash_table_insert(client_map, (gpointer)self->close, self->client);
85 g_hash_table_insert(client_map, (gpointer)self->desk, self->client);
86 g_hash_table_insert(client_map, (gpointer)self->icon, self->client);
87 g_hash_table_insert(client_map, (gpointer)self->iconify, self->client);
88 g_hash_table_insert(client_map, (gpointer)self->handle, self->client);
89 g_hash_table_insert(client_map, (gpointer)self->lgrip, self->client);
90 g_hash_table_insert(client_map, (gpointer)self->rgrip, self->client);
91
92 return self;
93 }
94
95 void frame_free(Frame *self)
96 {
97 /* remove all the windows for the frame from the client_map */
98 g_hash_table_remove(client_map, (gpointer)self->window);
99 g_hash_table_remove(client_map, (gpointer)self->plate);
100 g_hash_table_remove(client_map, (gpointer)self->title);
101 g_hash_table_remove(client_map, (gpointer)self->label);
102 g_hash_table_remove(client_map, (gpointer)self->max);
103 g_hash_table_remove(client_map, (gpointer)self->close);
104 g_hash_table_remove(client_map, (gpointer)self->desk);
105 g_hash_table_remove(client_map, (gpointer)self->icon);
106 g_hash_table_remove(client_map, (gpointer)self->iconify);
107 g_hash_table_remove(client_map, (gpointer)self->handle);
108 g_hash_table_remove(client_map, (gpointer)self->lgrip);
109 g_hash_table_remove(client_map, (gpointer)self->rgrip);
110
111 XDestroyWindow(ob_display, self->window);
112
113 g_free(self);
114 }
115
116 void frame_grab_client(Frame *self)
117 {
118 /* reparent the client to the frame */
119 XReparentWindow(ob_display, self->client->window, self->plate, 0, 0);
120 /*
121 When reparenting the client window, it is usually not mapped yet, since
122 this occurs from a MapRequest. However, in the case where Openbox is
123 starting up, the window is already mapped, so we'll see unmap events for
124 it. There are 2 unmap events generated that we see, one with the 'event'
125 member set the root window, and one set to the client, but both get
126 handled and need to be ignored.
127 */
128 if (ob_state == State_Starting)
129 self->client->ignore_unmaps += 2;
130
131 /* select the event mask on the client's parent (to receive config/map
132 req's) the ButtonPress is to catch clicks on the client border */
133 XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
134
135 /* map the client so it maps when the frame does */
136 XMapWindow(ob_display, self->client->window);
137
138 frame_adjust_size(self);
139 frame_adjust_position(self);
140 }
141
142 void frame_release_client(Frame *self)
143 {
144 XEvent ev;
145
146 /* check if the app has already reparented its window away */
147 if (XCheckTypedWindowEvent(ob_display, self->client->window,
148 ReparentNotify, &ev)) {
149 XPutBackEvent(ob_display, &ev);
150 /* re-map the window since the unmanaging process unmaps it */
151 XMapWindow(ob_display, self->client->window);
152 } else {
153 /* according to the ICCCM - if the client doesn't reparent itself,
154 then we will reparent the window to root for them */
155 XReparentWindow(ob_display, self->client->window, ob_root,
156 self->client->area.x, self->client->area.y);
157 }
158 }
159
160 void frame_show(Frame *self)
161 {
162 if (!self->visible) {
163 self->visible = TRUE;
164 XMapWindow(ob_display, self->window);
165 LOGICALHOOK(WindowShow, g_quark_try_string("client"), self->client);
166 }
167 }
168
169 void frame_hide(Frame *self)
170 {
171 if (self->visible) {
172 self->visible = FALSE;
173 self->client->ignore_unmaps++;
174 XUnmapWindow(ob_display, self->window);
175 LOGICALHOOK(WindowHide, g_quark_try_string("client"), self->client);
176 }
177 }
178
179 void frame_adjust_size(Frame *self)
180 {
181 self->decorations = self->client->decorations;
182
183 /* XXX set shit from the style */
184 self->geom.font_height = 10;
185 self->geom.bevel = 1;
186 self->geom.button_size = self->geom.font_height - 2;
187 self->geom.handle_height = 2;
188 self->geom.grip_width = self->geom.button_size * 2;
189 XResizeWindow(ob_display, self->lgrip, self->geom.grip_width,
190 self->geom.handle_height);
191 XResizeWindow(ob_display, self->rgrip, self->geom.grip_width,
192 self->geom.handle_height);
193
194
195
196
197 if (self->decorations & Decor_Border) {
198 self->geom.bwidth = 1;/*XXX style->frameBorderWidth(); */
199 self->geom.cbwidth = 1; /*XXX style->clientBorderWidth(); */
200 } else {
201 self->geom.bwidth = self->geom.cbwidth = 0;
202 }
203 STRUT_SET(self->innersize, self->geom.cbwidth, self->geom.cbwidth,
204 self->geom.cbwidth, self->geom.cbwidth);
205 self->geom.width = self->client->area.width + self->geom.cbwidth * 2;
206 g_assert(self->geom.width > 0);
207
208 /* set border widths */
209 XSetWindowBorderWidth(ob_display, self->plate, self->geom.cbwidth);
210 XSetWindowBorderWidth(ob_display, self->window, self->geom.bwidth);
211 XSetWindowBorderWidth(ob_display, self->title, self->geom.bwidth);
212 XSetWindowBorderWidth(ob_display, self->handle, self->geom.bwidth);
213 XSetWindowBorderWidth(ob_display, self->lgrip, self->geom.bwidth);
214 XSetWindowBorderWidth(ob_display, self->rgrip, self->geom.bwidth);
215
216 /* position/size and map/unmap all the windows */
217
218 if (self->decorations & Decor_Titlebar) {
219 self->geom.title_height = self->geom.font_height +
220 self->geom.bevel * 2;
221 XMoveResizeWindow(ob_display, self->title,
222 -self->geom.bwidth, -self->geom.bwidth,
223 self->geom.width, self->geom.title_height);
224 self->innersize.top += self->geom.title_height + self->geom.bwidth;
225 XMapWindow(ob_display, self->title);
226
227 /* layout the title bar elements */
228 /*XXX layoutTitle(); */
229 } else {
230 XUnmapWindow(ob_display, self->title);
231 /* make all the titlebar stuff not render */
232 self->decorations &= ~(Decor_Icon | Decor_Iconify |
233 Decor_Maximize | Decor_Close |
234 Decor_AllDesktops);
235 }
236
237 if (self->decorations & Decor_Handle) {
238 self->geom.handle_y = self->innersize.top +
239 self->client->area.height + self->geom.cbwidth;
240 XMoveResizeWindow(ob_display, self->handle,
241 -self->geom.bwidth, self->geom.handle_y,
242 self->geom.width, self->geom.handle_height);
243 XMoveWindow(ob_display, self->lgrip,
244 -self->geom.bwidth, -self->geom.bwidth);
245 XMoveWindow(ob_display, self->rgrip,
246 -self->geom.bwidth + self->geom.width -
247 self->geom.grip_width, -self->geom.bwidth);
248 self->innersize.bottom += self->geom.handle_height +
249 self->geom.bwidth;
250 XMapWindow(ob_display, self->handle);
251 } else
252 XUnmapWindow(ob_display, self->handle);
253
254 XResizeWindow(ob_display, self->window, self->geom.width,
255 (self->client->shaded ? self->geom.title_height :
256 self->innersize.top + self->innersize.bottom +
257 self->client->area.height));
258
259 /* do this in two steps because clients whose gravity is set to
260 'Static' don't end up getting moved at all with an XMoveResizeWindow */
261 XMoveWindow(ob_display, self->plate,
262 self->innersize.left - self->geom.cbwidth,
263 self->innersize.top - self->geom.cbwidth);
264 XResizeWindow(ob_display, self->plate, self->client->area.width,
265 self->client->area.height);
266
267 STRUT_SET(self->size,
268 self->innersize.left + self->geom.bwidth,
269 self->innersize.right + self->geom.bwidth,
270 self->innersize.top + self->geom.bwidth,
271 self->innersize.bottom + self->geom.bwidth);
272
273 RECT_SET_SIZE(self->area,
274 self->client->area.width +
275 self->size.left + self->size.right,
276 self->client->area.height +
277 self->size.top + self->size.bottom);
278
279 /*
280 // render all the elements
281 int screen = _client->screen();
282 bool focus = _client->focused();
283 if (_decorations & Client::Decor_Titlebar) {
284 render(screen, otk::Size(geom.width, geom.title_height()), _title,
285 &_title_sur, *(focus ? style->titlebarFocusBackground() :
286 style->titlebarUnfocusBackground()), false);
287
288 renderLabel();
289 renderMax();
290 renderDesk();
291 renderIconify();
292 renderIcon();
293 renderClose();
294 }
295
296 if (_decorations & Client::Decor_Handle) {
297 render(screen, otk::Size(geom.width, geom.handle_height), _handle,
298 &_handle_sur, *(focus ? style->handleFocusBackground() :
299 style->handleUnfocusBackground()));
300 render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip,
301 &_grip_sur, *(focus ? style->gripFocusBackground() :
302 style->gripUnfocusBackground()));
303 if ((focus ? style->gripFocusBackground() :
304 style->gripUnfocusBackground())->parentRelative())
305 XSetWindowBackgroundPixmap(**otk::display, _rgrip, ParentRelative);
306 else {
307 XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap());
308 }
309 XClearWindow(**otk::display, _rgrip);
310 }
311
312 XSetWindowBorder(**otk::display, _plate,
313 focus ? style->clientBorderFocusColor()->pixel() :
314 style->clientBorderUnfocusColor()->pixel());
315
316 */
317
318 frame_adjust_shape(self);
319 }
320
321 void frame_adjust_position(Frame *self)
322 {
323 self->area.x = self->client->area.x;
324 self->area.y = self->client->area.y;
325 frame_client_gravity(self, &self->area.x, &self->area.y);
326 XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
327 }
328
329 void frame_adjust_shape(Frame *self)
330 {
331 #ifdef SHAPE
332 int num;
333 XRectangle xrect[2];
334
335 if (!self->client->shaped) {
336 /* clear the shape on the frame window */
337 XShapeCombineMask(ob_display, self->window, ShapeBounding,
338 self->innersize.left,
339 self->innersize.top,
340 None, ShapeSet);
341 } else {
342 /* make the frame's shape match the clients */
343 XShapeCombineShape(ob_display, self->window, ShapeBounding,
344 self->innersize.left,
345 self->innersize.top,
346 self->client->window, ShapeBounding, ShapeSet);
347
348 num = 0;
349 if (self->decorations & Decor_Titlebar) {
350 xrect[0].x = -self->geom.bevel;
351 xrect[0].y = -self->geom.bevel;
352 xrect[0].width = self->geom.width + self->geom.bwidth * 2;
353 xrect[0].height = self->geom.title_height +
354 self->geom.bwidth * 2;
355 ++num;
356 }
357
358 if (self->decorations & Decor_Handle) {
359 xrect[1].x = -self->geom.bevel;
360 xrect[1].y = self->geom.handle_y;
361 xrect[1].width = self->geom.width + self->geom.bwidth * 2;
362 xrect[1].height = self->geom.handle_height +
363 self->geom.bwidth * 2;
364 ++num;
365 }
366
367 XShapeCombineRectangles(ob_display, self->window,
368 ShapeBounding, 0, 0, xrect, num,
369 ShapeUnion, Unsorted);
370 }
371 #endif
372 }
373
374 void frame_client_gravity(Frame *self, int *x, int *y)
375 {
376 /* horizontal */
377 switch (self->client->gravity) {
378 default:
379 case NorthWestGravity:
380 case SouthWestGravity:
381 case WestGravity:
382 break;
383
384 case NorthGravity:
385 case SouthGravity:
386 case CenterGravity:
387 *x -= (self->size.left + self->size.right) / 2;
388 break;
389
390 case NorthEastGravity:
391 case SouthEastGravity:
392 case EastGravity:
393 *x -= self->size.left + self->size.right;
394 break;
395
396 case ForgetGravity:
397 case StaticGravity:
398 *x -= self->size.left;
399 break;
400 }
401
402 /* vertical */
403 switch (self->client->gravity) {
404 default:
405 case NorthWestGravity:
406 case NorthEastGravity:
407 case NorthGravity:
408 break;
409
410 case CenterGravity:
411 case EastGravity:
412 case WestGravity:
413 *y -= (self->size.top + self->size.bottom) / 2;
414 break;
415
416 case SouthWestGravity:
417 case SouthEastGravity:
418 case SouthGravity:
419 *y -= self->size.top + self->size.bottom;
420 break;
421
422 case ForgetGravity:
423 case StaticGravity:
424 *y -= self->size.top;
425 break;
426 }
427 }
428
429 void frame_frame_gravity(Frame *self, int *x, int *y)
430 {
431 /* horizontal */
432 switch (self->client->gravity) {
433 default:
434 case NorthWestGravity:
435 case WestGravity:
436 case SouthWestGravity:
437 break;
438 case NorthGravity:
439 case CenterGravity:
440 case SouthGravity:
441 *x += (self->size.left + self->size.right) / 2;
442 break;
443 case NorthEastGravity:
444 case EastGravity:
445 case SouthEastGravity:
446 *x += self->size.left + self->size.right;
447 break;
448 case StaticGravity:
449 case ForgetGravity:
450 x += self->size.left;
451 break;
452 }
453
454 /* vertical */
455 switch (self->client->gravity) {
456 default:
457 case NorthWestGravity:
458 case WestGravity:
459 case SouthWestGravity:
460 break;
461 case NorthGravity:
462 case CenterGravity:
463 case SouthGravity:
464 *y += (self->size.top + self->size.bottom) / 2;
465 break;
466 case NorthEastGravity:
467 case EastGravity:
468 case SouthEastGravity:
469 *y += self->size.top + self->size.bottom;
470 break;
471 case StaticGravity:
472 case ForgetGravity:
473 *y += self->size.top;
474 break;
475 }
476 }
477
478 void frame_adjust_state(Frame *self)
479 {
480 /* XXX do shit.. buttons? */
481 }
482
483 void frame_adjust_focus(Frame *self)
484 {
485 /* XXX optimizations later... */
486 frame_adjust_size(self);
487 }
488
489 void frame_adjust_title(Frame *self)
490 {
491 /* XXX optimizations later... */
492 frame_adjust_size(self);
493 }
494
495 void frame_adjust_icon(Frame *self)
496 {
497 /* XXX render icon */
498 }
499
500 GQuark frame_get_context(Client *client, Window win)
501 {
502 Frame *self;
503
504 if (win == ob_root) return g_quark_try_string("root");
505 if (client == NULL) return g_quark_try_string("none");
506 if (win == client->window) return g_quark_try_string("client");
507
508 self = client->frame;
509 if (win == self->window) return g_quark_try_string("frame");
510 if (win == self->plate) return g_quark_try_string("frame");
511 if (win == self->title) return g_quark_try_string("titlebar");
512 if (win == self->label) return g_quark_try_string("titlebar");
513 if (win == self->handle) return g_quark_try_string("handle");
514 if (win == self->lgrip) return g_quark_try_string("blcorner");
515 if (win == self->rgrip) return g_quark_try_string("brcorner");
516
517 return g_quark_try_string("none");
518 }
519
520 void frame_startup(void)
521 {
522 g_quark_from_string("none");
523 g_quark_from_string("root");
524 g_quark_from_string("client");
525 g_quark_from_string("titlebar");
526 g_quark_from_string("handle");
527 g_quark_from_string("frame");
528 g_quark_from_string("blcorner");
529 g_quark_from_string("brcorner");
530 g_quark_from_string("tlcorner");
531 g_quark_from_string("trcorner");
532 g_quark_from_string("foo");
533 }
This page took 0.060255 seconds and 4 git commands to generate.