]> Dogcows Code - chaz/openbox/blob - src/Window.cc
fe13f4c1771fa05e37502b9dc8dfc51f6402e1d2
[chaz/openbox] / src / Window.cc
1 // Window.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // stupid macros needed to access some functions in version 2 of the GNU C
24 // library
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE
27 #endif // _GNU_SOURCE
28
29 #ifdef HAVE_CONFIG_H
30 # include "../config.h"
31 #endif // HAVE_CONFIG_H
32
33 #include <X11/Xatom.h>
34 #include <X11/keysym.h>
35
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #endif // HAVE_STRING_H
39
40 #ifdef DEBUG
41 # ifdef HAVE_STDIO_H
42 # include <stdio.h>
43 # endif // HAVE_STDIO_H
44 #endif // DEBUG
45
46 #include "i18n.h"
47 #include "openbox.h"
48 #include "Iconmenu.h"
49 #include "Screen.h"
50 #include "Toolbar.h"
51 #include "Window.h"
52 #include "Windowmenu.h"
53 #include "Workspace.h"
54 #ifdef SLIT
55 # include "Slit.h"
56 #endif // SLIT
57 #include "Util.h"
58
59 /*
60 * Initializes the class with default values/the window's set initial values.
61 */
62 OpenboxWindow::OpenboxWindow(Openbox &o, Window w, BScreen *s) : openbox(o) {
63 #ifdef DEBUG
64 fprintf(stderr, i18n->getMessage(WindowSet, WindowCreating,
65 "OpenboxWindow::OpenboxWindow(): creating 0x%lx\n"),
66 w);
67 #endif // DEBUG
68
69 client.window = w;
70 display = openbox.getXDisplay();
71
72 openbox.grab();
73 if (! validateClient()) return;
74
75 // fetch client size and placement
76 XWindowAttributes wattrib;
77 if ((! XGetWindowAttributes(display, client.window, &wattrib)) ||
78 (! wattrib.screen) || wattrib.override_redirect) {
79 #ifdef DEBUG
80 fprintf(stderr,
81 i18n->getMessage(WindowSet, WindowXGetWindowAttributesFail,
82 "OpenboxWindow::OpenboxWindow(): XGetWindowAttributes "
83 "failed\n"));
84 #endif // DEBUG
85
86 openbox.ungrab();
87 return;
88 }
89
90 if (s) {
91 screen = s;
92 } else {
93 screen = openbox.searchScreen(RootWindowOfScreen(wattrib.screen));
94 if (! screen) {
95 #ifdef DEBUG
96 fprintf(stderr, i18n->getMessage(WindowSet, WindowCannotFindScreen,
97 "OpenboxWindow::OpenboxWindow(): can't find screen\n"
98 "\tfor root window 0x%lx\n"),
99 RootWindowOfScreen(wattrib.screen));
100 #endif // DEBUG
101
102 openbox.ungrab();
103 return;
104 }
105 }
106
107 flags.moving = flags.resizing = flags.shaded = flags.visible =
108 flags.iconic = flags.transient = flags.focused =
109 flags.stuck = flags.modal = flags.send_focus_message =
110 flags.shaped = flags.managed = False;
111 flags.maximized = 0;
112
113 openbox_attrib.workspace = workspace_number = window_number = -1;
114
115 openbox_attrib.flags = openbox_attrib.attrib = openbox_attrib.stack
116 = openbox_attrib.decoration = 0l;
117 openbox_attrib.premax_x = openbox_attrib.premax_y = 0;
118 openbox_attrib.premax_w = openbox_attrib.premax_h = 0;
119
120 frame.window = frame.plate = frame.title = frame.handle = None;
121 frame.close_button = frame.iconify_button = frame.maximize_button = None;
122 frame.right_grip = frame.left_grip = None;
123
124 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
125 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
126 frame.pbutton = frame.ugrip = frame.fgrip = None;
127
128 decorations.titlebar = decorations.border = decorations.handle = True;
129 decorations.iconify = decorations.maximize = decorations.menu = True;
130 functions.resize = functions.move = functions.iconify =
131 functions.maximize = True;
132 functions.close = decorations.close = False;
133
134 client.wm_hint_flags = client.normal_hint_flags = 0;
135 client.transient_for = client.transient = 0;
136 client.title = 0;
137 client.title_len = 0;
138 client.icon_title = 0;
139 client.mwm_hint = (MwmHints *) 0;
140 client.openbox_hint = (OpenboxHints *) 0;
141
142 // get the initial size and location of client window (relative to the
143 // _root window_). This position is the reference point used with the
144 // window's gravity to find the window's initial position.
145 client.x = wattrib.x;
146 client.y = wattrib.y;
147 client.width = wattrib.width;
148 client.height = wattrib.height;
149 client.old_bw = wattrib.border_width;
150
151 windowmenu = 0;
152 lastButtonPressTime = 0;
153 image_ctrl = screen->getImageControl();
154
155 timer = new BTimer(openbox, *this);
156 timer->setTimeout(openbox.getAutoRaiseDelay());
157 timer->fireOnce(True);
158
159 getOpenboxHints();
160 if (! client.openbox_hint)
161 getMWMHints();
162
163 // get size, aspect, minimum/maximum size and other hints set by the
164 // client
165 getWMProtocols();
166 getWMHints();
167 getWMNormalHints();
168
169 #ifdef SLIT
170 if (client.initial_state == WithdrawnState) {
171 screen->getSlit()->addClient(client.window);
172 openbox.ungrab();
173 delete this;
174 return;
175 }
176 #endif // SLIT
177
178 flags.managed = True;
179 openbox.saveWindowSearch(client.window, this);
180
181 // determine if this is a transient window
182 Window win;
183 if (XGetTransientForHint(display, client.window, &win)) {
184 if (win && (win != client.window)) {
185 OpenboxWindow *tr;
186 if ((tr = openbox.searchWindow(win))) {
187 while (tr->client.transient) tr = tr->client.transient;
188 client.transient_for = tr;
189 tr->client.transient = this;
190 flags.stuck = client.transient_for->flags.stuck;
191 flags.transient = True;
192 } else if (win == client.window_group) {
193 if ((tr = openbox.searchGroup(win, this))) {
194 while (tr->client.transient) tr = tr->client.transient;
195 client.transient_for = tr;
196 tr->client.transient = this;
197 flags.stuck = client.transient_for->flags.stuck;
198 flags.transient = True;
199 }
200 }
201 }
202
203 if (win == screen->getRootWindow()) flags.modal = True;
204 }
205
206 // adjust the window decorations based on transience and window sizes
207 if (flags.transient)
208 decorations.maximize = decorations.handle = functions.maximize = False;
209
210 if ((client.normal_hint_flags & PMinSize) &&
211 (client.normal_hint_flags & PMaxSize) &&
212 client.max_width <= client.min_width &&
213 client.max_height <= client.min_height) {
214 decorations.maximize = decorations.handle =
215 functions.resize = functions.maximize = False;
216 }
217 upsize();
218
219 place_window = true;
220 if (openbox.isStartup() || flags.transient ||
221 client.normal_hint_flags & (PPosition|USPosition)) {
222 setGravityOffsets();
223
224 if ((openbox.isStartup()) ||
225 (frame.x >= 0 &&
226 (signed) (frame.y + frame.y_border) >= 0 &&
227 frame.x <= (signed) screen->size().w() &&
228 frame.y <= (signed) screen->size().h()))
229 place_window = false;
230 }
231
232 frame.window = createToplevelWindow(frame.x, frame.y, frame.width,
233 frame.height,
234 frame.border_w);
235 openbox.saveWindowSearch(frame.window, this);
236
237 frame.plate = createChildWindow(frame.window);
238 openbox.saveWindowSearch(frame.plate, this);
239
240 if (decorations.titlebar) {
241 frame.title = createChildWindow(frame.window);
242 frame.label = createChildWindow(frame.title);
243 openbox.saveWindowSearch(frame.title, this);
244 openbox.saveWindowSearch(frame.label, this);
245 }
246
247 if (decorations.handle) {
248 frame.handle = createChildWindow(frame.window);
249 openbox.saveWindowSearch(frame.handle, this);
250
251 frame.left_grip =
252 createChildWindow(frame.handle, openbox.getLowerLeftAngleCursor());
253 openbox.saveWindowSearch(frame.left_grip, this);
254
255 frame.right_grip =
256 createChildWindow(frame.handle, openbox.getLowerRightAngleCursor());
257 openbox.saveWindowSearch(frame.right_grip, this);
258 }
259
260 associateClientWindow();
261
262 if (! screen->sloppyFocus())
263 openbox.grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
264 GrabModeSync, GrabModeSync, None, None);
265
266 openbox.grabButton(Button1, Mod1Mask, frame.window, True,
267 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
268 GrabModeAsync, None, openbox.getMoveCursor());
269 openbox.grabButton(Button2, Mod1Mask, frame.window, True,
270 ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
271 openbox.grabButton(Button3, Mod1Mask, frame.window, True,
272 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
273 GrabModeAsync, None, None);
274
275 positionWindows();
276 XRaiseWindow(display, frame.plate);
277 XMapSubwindows(display, frame.plate);
278 if (decorations.titlebar) XMapSubwindows(display, frame.title);
279 XMapSubwindows(display, frame.window);
280
281 if (decorations.menu)
282 windowmenu = new Windowmenu(*this);
283
284 decorate();
285
286 if (workspace_number < 0 || workspace_number >= screen->getWorkspaceCount())
287 screen->getCurrentWorkspace()->addWindow(this, place_window);
288 else
289 screen->getWorkspace(workspace_number)->addWindow(this, place_window);
290
291 configure(frame.x, frame.y, frame.width, frame.height);
292
293 if (flags.shaded) {
294 flags.shaded = False;
295 shade();
296 }
297
298 if (flags.maximized && functions.maximize) {
299 unsigned int button = flags.maximized;
300 flags.maximized = 0;
301 maximize(button);
302 }
303
304 setFocusFlag(False);
305
306 openbox.ungrab();
307 }
308
309
310 OpenboxWindow::~OpenboxWindow(void) {
311 if (flags.moving || flags.resizing) {
312 screen->hideGeometry();
313 XUngrabPointer(display, CurrentTime);
314 }
315
316 if (workspace_number != -1 && window_number != -1)
317 screen->getWorkspace(workspace_number)->removeWindow(this);
318 else if (flags.iconic)
319 screen->removeIcon(this);
320
321 if (timer) {
322 if (timer->isTiming()) timer->stop();
323 delete timer;
324 }
325
326 if (windowmenu) delete windowmenu;
327
328 if (client.title)
329 delete [] client.title;
330
331 if (client.icon_title)
332 delete [] client.icon_title;
333
334 if (client.mwm_hint)
335 XFree(client.mwm_hint);
336
337 if (client.openbox_hint)
338 XFree(client.openbox_hint);
339
340 if (client.window_group)
341 openbox.removeGroupSearch(client.window_group);
342
343 if (flags.transient && client.transient_for)
344 client.transient_for->client.transient = client.transient;
345 if (client.transient)
346 client.transient->client.transient_for = client.transient_for;
347
348 if (frame.close_button) {
349 openbox.removeWindowSearch(frame.close_button);
350 XDestroyWindow(display, frame.close_button);
351 }
352
353 if (frame.iconify_button) {
354 openbox.removeWindowSearch(frame.iconify_button);
355 XDestroyWindow(display, frame.iconify_button);
356 }
357
358 if (frame.maximize_button) {
359 openbox.removeWindowSearch(frame.maximize_button);
360 XDestroyWindow(display, frame.maximize_button);
361 }
362
363 if (frame.title) {
364 if (frame.ftitle)
365 image_ctrl->removeImage(frame.ftitle);
366
367 if (frame.utitle)
368 image_ctrl->removeImage(frame.utitle);
369
370 if (frame.flabel)
371 image_ctrl->removeImage(frame.flabel);
372
373 if( frame.ulabel)
374 image_ctrl->removeImage(frame.ulabel);
375
376 openbox.removeWindowSearch(frame.label);
377 openbox.removeWindowSearch(frame.title);
378 XDestroyWindow(display, frame.label);
379 XDestroyWindow(display, frame.title);
380 }
381
382 if (frame.handle) {
383 if (frame.fhandle)
384 image_ctrl->removeImage(frame.fhandle);
385
386 if (frame.uhandle)
387 image_ctrl->removeImage(frame.uhandle);
388
389 if (frame.fgrip)
390 image_ctrl->removeImage(frame.fgrip);
391
392 if (frame.ugrip)
393 image_ctrl->removeImage(frame.ugrip);
394
395 openbox.removeWindowSearch(frame.handle);
396 openbox.removeWindowSearch(frame.right_grip);
397 openbox.removeWindowSearch(frame.left_grip);
398 XDestroyWindow(display, frame.right_grip);
399 XDestroyWindow(display, frame.left_grip);
400 XDestroyWindow(display, frame.handle);
401 }
402
403 if (frame.fbutton)
404 image_ctrl->removeImage(frame.fbutton);
405
406 if (frame.ubutton)
407 image_ctrl->removeImage(frame.ubutton);
408
409 if (frame.pbutton)
410 image_ctrl->removeImage(frame.pbutton);
411
412 if (frame.plate) {
413 openbox.removeWindowSearch(frame.plate);
414 XDestroyWindow(display, frame.plate);
415 }
416
417 if (frame.window) {
418 openbox.removeWindowSearch(frame.window);
419 XDestroyWindow(display, frame.window);
420 }
421
422 if (flags.managed) {
423 openbox.removeWindowSearch(client.window);
424 screen->removeNetizen(client.window);
425 }
426 }
427
428
429 /*
430 * Creates a new top level window, with a given location, size, and border
431 * width.
432 * Returns: the newly created window
433 */
434 Window OpenboxWindow::createToplevelWindow(int x, int y, unsigned int width,
435 unsigned int height,
436 unsigned int borderwidth)
437 {
438 XSetWindowAttributes attrib_create;
439 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
440 CWOverrideRedirect | CWEventMask;
441
442 attrib_create.background_pixmap = None;
443 attrib_create.colormap = screen->getColormap();
444 attrib_create.override_redirect = True;
445 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
446 ButtonMotionMask | EnterWindowMask;
447
448 return XCreateWindow(display, screen->getRootWindow(), x, y, width, height,
449 borderwidth, screen->getDepth(), InputOutput,
450 screen->getVisual(), create_mask,
451 &attrib_create);
452 }
453
454
455 /*
456 * Creates a child window, and optionally associates a given cursor with
457 * the new window.
458 */
459 Window OpenboxWindow::createChildWindow(Window parent, Cursor cursor) {
460 XSetWindowAttributes attrib_create;
461 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
462 CWEventMask;
463
464 attrib_create.background_pixmap = None;
465 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
466 ButtonMotionMask | ExposureMask |
467 EnterWindowMask | LeaveWindowMask;
468
469 if (cursor) {
470 create_mask |= CWCursor;
471 attrib_create.cursor = cursor;
472 }
473
474 return XCreateWindow(display, parent, 0, 0, 1, 1, 0, screen->getDepth(),
475 InputOutput, screen->getVisual(), create_mask,
476 &attrib_create);
477 }
478
479
480 void OpenboxWindow::associateClientWindow(void) {
481 XSetWindowBorderWidth(display, client.window, 0);
482 getWMName();
483 getWMIconName();
484
485 XChangeSaveSet(display, client.window, SetModeInsert);
486 XSetWindowAttributes attrib_set;
487
488 XSelectInput(display, frame.plate, NoEventMask);
489 XReparentWindow(display, client.window, frame.plate, 0, 0);
490 XSelectInput(display, frame.plate, SubstructureRedirectMask);
491
492 XFlush(display);
493
494 attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask |
495 FocusChangeMask;
496 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
497 ButtonMotionMask;
498
499 XChangeWindowAttributes(display, client.window, CWEventMask|CWDontPropagate,
500 &attrib_set);
501
502 #ifdef SHAPE
503 if (openbox.hasShapeExtensions()) {
504 XShapeSelectInput(display, client.window, ShapeNotifyMask);
505
506 int foo;
507 unsigned int ufoo;
508
509 XShapeQueryExtents(display, client.window, &flags.shaped, &foo, &foo,
510 &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, &ufoo);
511
512 if (flags.shaped) {
513 XShapeCombineShape(display, frame.window, ShapeBounding,
514 frame.mwm_border_w, frame.y_border +
515 frame.mwm_border_w, client.window,
516 ShapeBounding, ShapeSet);
517
518 int num = 1;
519 XRectangle xrect[2];
520 xrect[0].x = xrect[0].y = 0;
521 xrect[0].width = frame.width;
522 xrect[0].height = frame.y_border;
523
524 if (decorations.handle) {
525 xrect[1].x = 0;
526 xrect[1].y = frame.y_handle;
527 xrect[1].width = frame.width;
528 xrect[1].height = frame.handle_h + frame.border_w;
529 num++;
530 }
531
532 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
533 xrect, num, ShapeUnion, Unsorted);
534 }
535 }
536 #endif // SHAPE
537
538 if (decorations.iconify) createIconifyButton();
539 if (decorations.maximize) createMaximizeButton();
540 if (decorations.close) createCloseButton();
541 }
542
543
544 void OpenboxWindow::decorate(void) {
545 Pixmap tmp = frame.fbutton;
546 BTexture *texture = &(screen->getWindowStyle()->b_focus);
547 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
548 frame.fbutton = None;
549 frame.fbutton_pixel = texture->getColor()->getPixel();
550 } else {
551 frame.fbutton =
552 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
553 }
554 if (tmp) image_ctrl->removeImage(tmp);
555
556 tmp = frame.ubutton;
557 texture = &(screen->getWindowStyle()->b_unfocus);
558 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
559 frame.ubutton = None;
560 frame.ubutton_pixel = texture->getColor()->getPixel();
561 } else {
562 frame.ubutton =
563 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
564 }
565 if (tmp) image_ctrl->removeImage(tmp);
566
567 tmp = frame.pbutton;
568 texture = &(screen->getWindowStyle()->b_pressed);
569 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
570 frame.pbutton = None;
571 frame.pbutton_pixel = texture->getColor()->getPixel();
572 } else {
573 frame.pbutton =
574 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
575 }
576 if (tmp) image_ctrl->removeImage(tmp);
577
578 if (decorations.titlebar) {
579 tmp = frame.ftitle;
580 texture = &(screen->getWindowStyle()->t_focus);
581 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
582 frame.ftitle = None;
583 frame.ftitle_pixel = texture->getColor()->getPixel();
584 } else {
585 frame.ftitle =
586 image_ctrl->renderImage(frame.width, frame.title_h, texture);
587 }
588 if (tmp) image_ctrl->removeImage(tmp);
589
590 tmp = frame.utitle;
591 texture = &(screen->getWindowStyle()->t_unfocus);
592 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
593 frame.utitle = None;
594 frame.utitle_pixel = texture->getColor()->getPixel();
595 } else {
596 frame.utitle =
597 image_ctrl->renderImage(frame.width, frame.title_h, texture);
598 }
599 if (tmp) image_ctrl->removeImage(tmp);
600
601 XSetWindowBorder(display, frame.title,
602 screen->getBorderColor()->getPixel());
603
604 decorateLabel();
605 }
606
607 if (decorations.border) {
608 frame.fborder_pixel = screen->getWindowStyle()->f_focus.getPixel();
609 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.getPixel();
610 openbox_attrib.flags |= AttribDecoration;
611 openbox_attrib.decoration = DecorNormal;
612 } else {
613 openbox_attrib.flags |= AttribDecoration;
614 openbox_attrib.decoration = DecorNone;
615 }
616
617 if (decorations.handle) {
618 tmp = frame.fhandle;
619 texture = &(screen->getWindowStyle()->h_focus);
620 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
621 frame.fhandle = None;
622 frame.fhandle_pixel = texture->getColor()->getPixel();
623 } else {
624 frame.fhandle =
625 image_ctrl->renderImage(frame.width, frame.handle_h, texture);
626 }
627 if (tmp) image_ctrl->removeImage(tmp);
628
629 tmp = frame.uhandle;
630 texture = &(screen->getWindowStyle()->h_unfocus);
631 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
632 frame.uhandle = None;
633 frame.uhandle_pixel = texture->getColor()->getPixel();
634 } else {
635 frame.uhandle =
636 image_ctrl->renderImage(frame.width, frame.handle_h, texture);
637 }
638 if (tmp) image_ctrl->removeImage(tmp);
639
640 tmp = frame.fgrip;
641 texture = &(screen->getWindowStyle()->g_focus);
642 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
643 frame.fgrip = None;
644 frame.fgrip_pixel = texture->getColor()->getPixel();
645 } else {
646 frame.fgrip =
647 image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture);
648 }
649 if (tmp) image_ctrl->removeImage(tmp);
650
651 tmp = frame.ugrip;
652 texture = &(screen->getWindowStyle()->g_unfocus);
653 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
654 frame.ugrip = None;
655 frame.ugrip_pixel = texture->getColor()->getPixel();
656 } else {
657 frame.ugrip =
658 image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture);
659 }
660 if (tmp) image_ctrl->removeImage(tmp);
661
662 XSetWindowBorder(display, frame.handle,
663 screen->getBorderColor()->getPixel());
664 XSetWindowBorder(display, frame.left_grip,
665 screen->getBorderColor()->getPixel());
666 XSetWindowBorder(display, frame.right_grip,
667 screen->getBorderColor()->getPixel());
668 }
669
670 XSetWindowBorder(display, frame.window,
671 screen->getBorderColor()->getPixel());
672 }
673
674
675 void OpenboxWindow::decorateLabel(void) {
676 Pixmap tmp = frame.flabel;
677 BTexture *texture = &(screen->getWindowStyle()->l_focus);
678 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
679 frame.flabel = None;
680 frame.flabel_pixel = texture->getColor()->getPixel();
681 } else {
682 frame.flabel =
683 image_ctrl->renderImage(frame.label_w, frame.label_h, texture);
684 }
685 if (tmp) image_ctrl->removeImage(tmp);
686
687 tmp = frame.ulabel;
688 texture = &(screen->getWindowStyle()->l_unfocus);
689 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
690 frame.ulabel = None;
691 frame.ulabel_pixel = texture->getColor()->getPixel();
692 } else {
693 frame.ulabel =
694 image_ctrl->renderImage(frame.label_w, frame.label_h, texture);
695 }
696 if (tmp) image_ctrl->removeImage(tmp);
697 }
698
699
700 void OpenboxWindow::createCloseButton(void) {
701 if (decorations.close && frame.title != None) {
702 frame.close_button = createChildWindow(frame.title);
703 openbox.saveWindowSearch(frame.close_button, this);
704 }
705 }
706
707
708 void OpenboxWindow::createIconifyButton(void) {
709 if (decorations.iconify && frame.title != None) {
710 frame.iconify_button = createChildWindow(frame.title);
711 openbox.saveWindowSearch(frame.iconify_button, this);
712 }
713 }
714
715
716 void OpenboxWindow::createMaximizeButton(void) {
717 if (decorations.maximize && frame.title != None) {
718 frame.maximize_button = createChildWindow(frame.title);
719 openbox.saveWindowSearch(frame.maximize_button, this);
720 }
721 }
722
723
724 void OpenboxWindow::positionButtons(Bool redecorate_label) {
725 const char *format = openbox.getTitleBarLayout();
726 const unsigned int bw = frame.bevel_w + 1;
727 const unsigned int by = frame.bevel_w + 1;
728 unsigned int bx = frame.bevel_w + 1;
729 unsigned int bcount = strlen(format) - 1;
730
731 if (!decorations.close)
732 bcount--;
733 if (!decorations.maximize)
734 bcount--;
735 if (!decorations.iconify)
736 bcount--;
737 frame.label_w = frame.width - bx * 2 - (frame.button_w + bw) * bcount;
738
739 bool hasclose, hasiconify, hasmaximize;
740 hasclose = hasiconify = hasmaximize = false;
741
742 for (int i = 0; format[i] != '\0' && i < 4; i++) {
743 switch(format[i]) {
744 case 'C':
745 if (decorations.close) {
746 if (frame.close_button == None)
747 createCloseButton();
748 XMoveResizeWindow(display, frame.close_button, bx, by,
749 frame.button_w, frame.button_h);
750 XMapWindow(display, frame.close_button);
751 XClearWindow(display, frame.close_button);
752 bx += frame.button_w + bw;
753 hasclose = true;
754 }
755 break;
756 case 'I':
757 if (decorations.iconify) {
758 if (frame.iconify_button == None)
759 createIconifyButton();
760 XMoveResizeWindow(display, frame.iconify_button, bx, by,
761 frame.button_w, frame.button_h);
762 XMapWindow(display, frame.iconify_button);
763 XClearWindow(display, frame.iconify_button);
764 bx += frame.button_w + bw;
765 hasiconify = true;
766 }
767 break;
768 case 'M':
769 if (decorations.maximize) {
770 if (frame.maximize_button == None)
771 createMaximizeButton();
772 XMoveResizeWindow(display, frame.maximize_button, bx, by,
773 frame.button_w, frame.button_h);
774 XMapWindow(display, frame.maximize_button);
775 XClearWindow(display, frame.maximize_button);
776 bx += frame.button_w + bw;
777 hasmaximize = true;
778 }
779 break;
780 case 'L':
781 XMoveResizeWindow(display, frame.label, bx, by - 1,
782 frame.label_w, frame.label_h);
783 bx += frame.label_w + bw;
784 break;
785 }
786 }
787
788 if (!hasclose) {
789 openbox.removeWindowSearch(frame.close_button);
790 XDestroyWindow(display, frame.close_button);
791 frame.close_button = None;
792 }
793 if (!hasiconify) {
794 openbox.removeWindowSearch(frame.iconify_button);
795 XDestroyWindow(display, frame.iconify_button);
796 frame.iconify_button = None;
797 }
798 if (!hasmaximize) {
799 openbox.removeWindowSearch(frame.maximize_button);
800 XDestroyWindow(display, frame.maximize_button);
801 frame.maximize_button = None;
802 }
803 if (redecorate_label)
804 decorateLabel();
805 redrawLabel();
806 redrawAllButtons();
807 }
808
809
810 void OpenboxWindow::reconfigure(void) {
811 upsize();
812
813 client.x = frame.x + frame.mwm_border_w + frame.border_w;
814 client.y = frame.y + frame.y_border + frame.mwm_border_w +
815 frame.border_w;
816
817 if (client.title) {
818 if (i18n->multibyte()) {
819 XRectangle ink, logical;
820 XmbTextExtents(screen->getWindowStyle()->fontset,
821 client.title, client.title_len, &ink, &logical);
822 client.title_text_w = logical.width;
823 } else {
824 client.title_text_w = XTextWidth(screen->getWindowStyle()->font,
825 client.title, client.title_len);
826 }
827 client.title_text_w += (frame.bevel_w * 4);
828 }
829
830 positionWindows();
831 decorate();
832
833 XClearWindow(display, frame.window);
834 setFocusFlag(flags.focused);
835
836 configure(frame.x, frame.y, frame.width, frame.height);
837
838 if (! screen->sloppyFocus())
839 openbox.grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
840 GrabModeSync, GrabModeSync, None, None);
841 else
842 openbox.ungrabButton(Button1, 0, frame.plate);
843
844 if (windowmenu) {
845 windowmenu->move(windowmenu->getX(), frame.y + frame.title_h);
846 windowmenu->reconfigure();
847 }
848 }
849
850
851 void OpenboxWindow::positionWindows(void) {
852 XResizeWindow(display, frame.window, frame.width,
853 ((flags.shaded) ? frame.title_h : frame.height));
854 XSetWindowBorderWidth(display, frame.window, frame.border_w);
855 XSetWindowBorderWidth(display, frame.plate, frame.mwm_border_w);
856 XMoveResizeWindow(display, frame.plate, 0, frame.y_border,
857 client.width, client.height);
858 XMoveResizeWindow(display, client.window, 0, 0, client.width, client.height);
859
860 if (decorations.titlebar) {
861 XSetWindowBorderWidth(display, frame.title, frame.border_w);
862 XMoveResizeWindow(display, frame.title, -frame.border_w,
863 -frame.border_w, frame.width, frame.title_h);
864
865 positionButtons();
866 } else if (frame.title) {
867 XUnmapWindow(display, frame.title);
868 }
869 if (decorations.handle) {
870 XSetWindowBorderWidth(display, frame.handle, frame.border_w);
871 XSetWindowBorderWidth(display, frame.left_grip, frame.border_w);
872 XSetWindowBorderWidth(display, frame.right_grip, frame.border_w);
873
874 XMoveResizeWindow(display, frame.handle, -frame.border_w,
875 frame.y_handle - frame.border_w,
876 frame.width, frame.handle_h);
877 XMoveResizeWindow(display, frame.left_grip, -frame.border_w,
878 -frame.border_w, frame.grip_w, frame.grip_h);
879 XMoveResizeWindow(display, frame.right_grip,
880 frame.width - frame.grip_w - frame.border_w,
881 -frame.border_w, frame.grip_w, frame.grip_h);
882 XMapSubwindows(display, frame.handle);
883 } else if (frame.handle) {
884 XUnmapWindow(display, frame.handle);
885 }
886 }
887
888
889 void OpenboxWindow::getWMName(void) {
890 if (client.title) {
891 delete [] client.title;
892 client.title = (char *) 0;
893 }
894
895 XTextProperty text_prop;
896 char **list;
897 int num;
898
899 if (XGetWMName(display, client.window, &text_prop)) {
900 if (text_prop.value && text_prop.nitems > 0) {
901 if (text_prop.encoding != XA_STRING) {
902 text_prop.nitems = strlen((char *) text_prop.value);
903
904 if ((XmbTextPropertyToTextList(display, &text_prop,
905 &list, &num) == Success) &&
906 (num > 0) && *list) {
907 client.title = bstrdup(*list);
908 XFreeStringList(list);
909 } else {
910 client.title = bstrdup((char *) text_prop.value);
911 }
912 } else {
913 client.title = bstrdup((char *) text_prop.value);
914 }
915 XFree((char *) text_prop.value);
916 } else {
917 client.title = bstrdup(i18n->getMessage(WindowSet, WindowUnnamed,
918 "Unnamed"));
919 }
920 } else {
921 client.title = bstrdup(i18n->getMessage(WindowSet, WindowUnnamed,
922 "Unnamed"));
923 }
924 client.title_len = strlen(client.title);
925
926 if (i18n->multibyte()) {
927 XRectangle ink, logical;
928 XmbTextExtents(screen->getWindowStyle()->fontset,
929 client.title, client.title_len, &ink, &logical);
930 client.title_text_w = logical.width;
931 } else {
932 client.title_len = strlen(client.title);
933 client.title_text_w = XTextWidth(screen->getWindowStyle()->font,
934 client.title, client.title_len);
935 }
936
937 client.title_text_w += (frame.bevel_w * 4);
938 }
939
940
941 void OpenboxWindow::getWMIconName(void) {
942 if (client.icon_title) {
943 delete [] client.icon_title;
944 client.icon_title = (char *) 0;
945 }
946
947 XTextProperty text_prop;
948 char **list;
949 int num;
950
951 if (XGetWMIconName(display, client.window, &text_prop)) {
952 if (text_prop.value && text_prop.nitems > 0) {
953 if (text_prop.encoding != XA_STRING) {
954 text_prop.nitems = strlen((char *) text_prop.value);
955
956 if ((XmbTextPropertyToTextList(display, &text_prop,
957 &list, &num) == Success) &&
958 (num > 0) && *list) {
959 client.icon_title = bstrdup(*list);
960 XFreeStringList(list);
961 } else {
962 client.icon_title = bstrdup((char *) text_prop.value);
963 }
964 } else {
965 client.icon_title = bstrdup((char *) text_prop.value);
966 }
967 XFree((char *) text_prop.value);
968 } else {
969 client.icon_title = bstrdup(client.title);
970 }
971 } else {
972 client.icon_title = bstrdup(client.title);
973 }
974 }
975
976
977 /*
978 * Retrieve which WM Protocols are supported by the client window.
979 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
980 * window's decorations and allow the close behavior.
981 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
982 * this.
983 */
984 void OpenboxWindow::getWMProtocols(void) {
985 Atom *proto;
986 int num_return = 0;
987
988 if (XGetWMProtocols(display, client.window, &proto, &num_return)) {
989 for (int i = 0; i < num_return; ++i) {
990 if (proto[i] == openbox.getWMDeleteAtom())
991 functions.close = decorations.close = True;
992 else if (proto[i] == openbox.getWMTakeFocusAtom())
993 flags.send_focus_message = True;
994 else if (proto[i] == openbox.getOpenboxStructureMessagesAtom())
995 screen->addNetizen(new Netizen(*screen, client.window));
996 }
997
998 XFree(proto);
999 }
1000 }
1001
1002
1003 /*
1004 * Gets the value of the WM_HINTS property.
1005 * If the property is not set, then use a set of default values.
1006 */
1007 void OpenboxWindow::getWMHints(void) {
1008 XWMHints *wmhint = XGetWMHints(display, client.window);
1009 if (! wmhint) {
1010 flags.visible = True;
1011 flags.iconic = False;
1012 focus_mode = F_Passive;
1013 client.window_group = None;
1014 client.initial_state = NormalState;
1015 return;
1016 }
1017 client.wm_hint_flags = wmhint->flags;
1018 if (wmhint->flags & InputHint) {
1019 if (wmhint->input == True) {
1020 if (flags.send_focus_message)
1021 focus_mode = F_LocallyActive;
1022 else
1023 focus_mode = F_Passive;
1024 } else {
1025 if (flags.send_focus_message)
1026 focus_mode = F_GloballyActive;
1027 else
1028 focus_mode = F_NoInput;
1029 }
1030 } else {
1031 focus_mode = F_Passive;
1032 }
1033
1034 if (wmhint->flags & StateHint)
1035 client.initial_state = wmhint->initial_state;
1036 else
1037 client.initial_state = NormalState;
1038
1039 if (wmhint->flags & WindowGroupHint) {
1040 if (! client.window_group) {
1041 client.window_group = wmhint->window_group;
1042 openbox.saveGroupSearch(client.window_group, this);
1043 }
1044 } else {
1045 client.window_group = None;
1046 }
1047 XFree(wmhint);
1048 }
1049
1050
1051 /*
1052 * Gets the value of the WM_NORMAL_HINTS property.
1053 * If the property is not set, then use a set of default values.
1054 */
1055 void OpenboxWindow::getWMNormalHints(void) {
1056 long icccm_mask;
1057 XSizeHints sizehint;
1058
1059 client.min_width = client.min_height =
1060 client.base_width = client.base_height =
1061 client.width_inc = client.height_inc = 1;
1062 client.max_width = screen->size().w();
1063 client.max_height = screen->size().h();
1064 client.min_aspect_x = client.min_aspect_y =
1065 client.max_aspect_x = client.max_aspect_y = 1;
1066 client.win_gravity = NorthWestGravity;
1067
1068 if (! XGetWMNormalHints(display, client.window, &sizehint, &icccm_mask))
1069 return;
1070
1071 client.normal_hint_flags = sizehint.flags;
1072
1073 if (sizehint.flags & PMinSize) {
1074 client.min_width = sizehint.min_width;
1075 client.min_height = sizehint.min_height;
1076 }
1077
1078 if (sizehint.flags & PMaxSize) {
1079 client.max_width = sizehint.max_width;
1080 client.max_height = sizehint.max_height;
1081 }
1082
1083 if (sizehint.flags & PResizeInc) {
1084 client.width_inc = sizehint.width_inc;
1085 client.height_inc = sizehint.height_inc;
1086 }
1087
1088 if (sizehint.flags & PAspect) {
1089 client.min_aspect_x = sizehint.min_aspect.x;
1090 client.min_aspect_y = sizehint.min_aspect.y;
1091 client.max_aspect_x = sizehint.max_aspect.x;
1092 client.max_aspect_y = sizehint.max_aspect.y;
1093 }
1094
1095 if (sizehint.flags & PBaseSize) {
1096 client.base_width = sizehint.base_width;
1097 client.base_height = sizehint.base_height;
1098 }
1099
1100 if (sizehint.flags & PWinGravity)
1101 client.win_gravity = sizehint.win_gravity;
1102 }
1103
1104
1105 /*
1106 * Gets the MWM hints for the class' contained window.
1107 * This is used while initializing the window to its first state, and not
1108 * thereafter.
1109 * Returns: true if the MWM hints are successfully retreived and applied; false
1110 * if they are not.
1111 */
1112 void OpenboxWindow::getMWMHints(void) {
1113 int format;
1114 Atom atom_return;
1115 unsigned long num, len;
1116
1117 int ret = XGetWindowProperty(display, client.window,
1118 openbox.getMotifWMHintsAtom(), 0,
1119 PropMwmHintsElements, False,
1120 openbox.getMotifWMHintsAtom(), &atom_return,
1121 &format, &num, &len,
1122 (unsigned char **) &client.mwm_hint);
1123
1124 if (ret != Success || !client.mwm_hint || num != PropMwmHintsElements)
1125 return;
1126
1127 if (client.mwm_hint->flags & MwmHintsDecorations) {
1128 if (client.mwm_hint->decorations & MwmDecorAll) {
1129 decorations.titlebar = decorations.handle = decorations.border =
1130 decorations.iconify = decorations.maximize =
1131 decorations.close = decorations.menu = True;
1132 } else {
1133 decorations.titlebar = decorations.handle = decorations.border =
1134 decorations.iconify = decorations.maximize =
1135 decorations.close = decorations.menu = False;
1136
1137 if (client.mwm_hint->decorations & MwmDecorBorder)
1138 decorations.border = True;
1139 if (client.mwm_hint->decorations & MwmDecorHandle)
1140 decorations.handle = True;
1141 if (client.mwm_hint->decorations & MwmDecorTitle)
1142 decorations.titlebar = True;
1143 if (client.mwm_hint->decorations & MwmDecorMenu)
1144 decorations.menu = True;
1145 if (client.mwm_hint->decorations & MwmDecorIconify)
1146 decorations.iconify = True;
1147 if (client.mwm_hint->decorations & MwmDecorMaximize)
1148 decorations.maximize = True;
1149 }
1150 }
1151
1152 if (client.mwm_hint->flags & MwmHintsFunctions) {
1153 if (client.mwm_hint->functions & MwmFuncAll) {
1154 functions.resize = functions.move = functions.iconify =
1155 functions.maximize = functions.close = True;
1156 } else {
1157 functions.resize = functions.move = functions.iconify =
1158 functions.maximize = functions.close = False;
1159
1160 if (client.mwm_hint->functions & MwmFuncResize)
1161 functions.resize = True;
1162 if (client.mwm_hint->functions & MwmFuncMove)
1163 functions.move = True;
1164 if (client.mwm_hint->functions & MwmFuncIconify)
1165 functions.iconify = True;
1166 if (client.mwm_hint->functions & MwmFuncMaximize)
1167 functions.maximize = True;
1168 if (client.mwm_hint->functions & MwmFuncClose)
1169 functions.close = True;
1170 }
1171 }
1172 }
1173
1174
1175 /*
1176 * Gets the openbox hints from the class' contained window.
1177 * This is used while initializing the window to its first state, and not
1178 * thereafter.
1179 * Returns: true if the hints are successfully retreived and applied; false if
1180 * they are not.
1181 */
1182 void OpenboxWindow::getOpenboxHints(void) {
1183 int format;
1184 Atom atom_return;
1185 unsigned long num, len;
1186
1187 int ret = XGetWindowProperty(display, client.window,
1188 openbox.getOpenboxHintsAtom(), 0,
1189 PropOpenboxHintsElements, False,
1190 openbox.getOpenboxHintsAtom(), &atom_return,
1191 &format, &num, &len,
1192 (unsigned char **) &client.openbox_hint);
1193 if (ret != Success || !client.openbox_hint ||
1194 num != PropOpenboxHintsElements)
1195 return;
1196
1197 if (client.openbox_hint->flags & AttribShaded)
1198 flags.shaded = (client.openbox_hint->attrib & AttribShaded);
1199
1200 if ((client.openbox_hint->flags & AttribMaxHoriz) &&
1201 (client.openbox_hint->flags & AttribMaxVert))
1202 flags.maximized = (client.openbox_hint->attrib &
1203 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1204 else if (client.openbox_hint->flags & AttribMaxVert)
1205 flags.maximized = (client.openbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1206 else if (client.openbox_hint->flags & AttribMaxHoriz)
1207 flags.maximized = (client.openbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1208
1209 if (client.openbox_hint->flags & AttribOmnipresent)
1210 flags.stuck = (client.openbox_hint->attrib & AttribOmnipresent);
1211
1212 if (client.openbox_hint->flags & AttribWorkspace)
1213 workspace_number = client.openbox_hint->workspace;
1214
1215 // if (client.openbox_hint->flags & AttribStack)
1216 // don't yet have always on top/bottom for openbox yet... working
1217 // on that
1218
1219 if (client.openbox_hint->flags & AttribDecoration) {
1220 switch (client.openbox_hint->decoration) {
1221 case DecorNone:
1222 decorations.titlebar = decorations.border = decorations.handle =
1223 decorations.iconify = decorations.maximize =
1224 decorations.menu = False;
1225 functions.resize = functions.move = functions.iconify =
1226 functions.maximize = False;
1227
1228 break;
1229
1230 case DecorTiny:
1231 decorations.titlebar = decorations.iconify = decorations.menu =
1232 functions.move = functions.iconify = True;
1233 decorations.border = decorations.handle = decorations.maximize =
1234 functions.resize = functions.maximize = False;
1235
1236 break;
1237
1238 case DecorTool:
1239 decorations.titlebar = decorations.menu = functions.move = True;
1240 decorations.iconify = decorations.border = decorations.handle =
1241 decorations.maximize = functions.resize = functions.maximize =
1242 functions.iconify = False;
1243
1244 break;
1245
1246 case DecorNormal:
1247 default:
1248 decorations.titlebar = decorations.border = decorations.handle =
1249 decorations.iconify = decorations.maximize =
1250 decorations.menu = True;
1251 functions.resize = functions.move = functions.iconify =
1252 functions.maximize = True;
1253
1254 break;
1255 }
1256
1257 reconfigure();
1258 }
1259 }
1260
1261
1262 void OpenboxWindow::configure(int dx, int dy,
1263 unsigned int dw, unsigned int dh) {
1264 Bool send_event = (frame.x != dx || frame.y != dy);
1265
1266 if ((dw != frame.width) || (dh != frame.height)) {
1267 if ((((signed) frame.width) + dx) < 0) dx = 0;
1268 if ((((signed) frame.height) + dy) < 0) dy = 0;
1269
1270 frame.x = dx;
1271 frame.y = dy;
1272 frame.width = dw;
1273 frame.height = dh;
1274
1275 downsize();
1276
1277 #ifdef SHAPE
1278 if (openbox.hasShapeExtensions() && flags.shaped) {
1279 XShapeCombineShape(display, frame.window, ShapeBounding,
1280 frame.mwm_border_w, frame.y_border +
1281 frame.mwm_border_w, client.window,
1282 ShapeBounding, ShapeSet);
1283
1284 int num = 1;
1285 XRectangle xrect[2];
1286 xrect[0].x = xrect[0].y = 0;
1287 xrect[0].width = frame.width;
1288 xrect[0].height = frame.y_border;
1289
1290 if (decorations.handle) {
1291 xrect[1].x = 0;
1292 xrect[1].y = frame.y_handle;
1293 xrect[1].width = frame.width;
1294 xrect[1].height = frame.handle_h + frame.border_w;
1295 num++;
1296 }
1297
1298 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
1299 xrect, num, ShapeUnion, Unsorted);
1300 }
1301 #endif // SHAPE
1302
1303 XMoveWindow(display, frame.window, frame.x, frame.y);
1304
1305 positionWindows();
1306 decorate();
1307 setFocusFlag(flags.focused);
1308 redrawAllButtons();
1309 } else {
1310 frame.x = dx;
1311 frame.y = dy;
1312
1313 XMoveWindow(display, frame.window, frame.x, frame.y);
1314
1315 if (! flags.moving) send_event = True;
1316 }
1317
1318 if (send_event && ! flags.moving) {
1319 client.x = dx + frame.mwm_border_w + frame.border_w;
1320 client.y = dy + frame.y_border + frame.mwm_border_w +
1321 frame.border_w;
1322
1323 XEvent event;
1324 event.type = ConfigureNotify;
1325
1326 event.xconfigure.display = display;
1327 event.xconfigure.event = client.window;
1328 event.xconfigure.window = client.window;
1329 event.xconfigure.x = client.x;
1330 event.xconfigure.y = client.y;
1331 event.xconfigure.width = client.width;
1332 event.xconfigure.height = client.height;
1333 event.xconfigure.border_width = client.old_bw;
1334 event.xconfigure.above = frame.window;
1335 event.xconfigure.override_redirect = False;
1336
1337 XSendEvent(display, client.window, True, NoEventMask, &event);
1338
1339 screen->updateNetizenConfigNotify(&event);
1340 }
1341 }
1342
1343
1344 bool OpenboxWindow::setInputFocus(void) {
1345 if (((signed) (frame.x + frame.width)) < 0) {
1346 if (((signed) (frame.y + frame.y_border)) < 0)
1347 configure(frame.border_w, frame.border_w, frame.width, frame.height);
1348 else if (frame.y > (signed) screen->size().h())
1349 configure(frame.border_w, screen->size().h() - frame.height,
1350 frame.width, frame.height);
1351 else
1352 configure(frame.border_w, frame.y + frame.border_w,
1353 frame.width, frame.height);
1354 } else if (frame.x > (signed) screen->size().w()) {
1355 if (((signed) (frame.y + frame.y_border)) < 0)
1356 configure(screen->size().w() - frame.width, frame.border_w,
1357 frame.width, frame.height);
1358 else if (frame.y > (signed) screen->size().h())
1359 configure(screen->size().w() - frame.width,
1360 screen->size().h() - frame.height, frame.width, frame.height);
1361 else
1362 configure(screen->size().w() - frame.width,
1363 frame.y + frame.border_w, frame.width, frame.height);
1364 }
1365
1366 openbox.grab();
1367 if (! validateClient()) return False;
1368
1369 bool ret = false;
1370
1371 if (client.transient && flags.modal) {
1372 ret = client.transient->setInputFocus();
1373 } else if (! flags.focused) {
1374 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1375 XSetInputFocus(display, client.window,
1376 RevertToPointerRoot, CurrentTime);
1377 openbox.focusWindow(this);
1378
1379 if (flags.send_focus_message) {
1380 XEvent ce;
1381 ce.xclient.type = ClientMessage;
1382 ce.xclient.message_type = openbox.getWMProtocolsAtom();
1383 ce.xclient.display = display;
1384 ce.xclient.window = client.window;
1385 ce.xclient.format = 32;
1386 ce.xclient.data.l[0] = openbox.getWMTakeFocusAtom();
1387 ce.xclient.data.l[1] = openbox.getLastTime();
1388 ce.xclient.data.l[2] = 0l;
1389 ce.xclient.data.l[3] = 0l;
1390 ce.xclient.data.l[4] = 0l;
1391 XSendEvent(display, client.window, False, NoEventMask, &ce);
1392 }
1393
1394 if (screen->sloppyFocus() && screen->autoRaise())
1395 timer->start();
1396
1397 ret = true;
1398 }
1399 }
1400
1401 openbox.ungrab();
1402
1403 return ret;
1404 }
1405
1406
1407 void OpenboxWindow::iconify(void) {
1408 if (flags.iconic) return;
1409
1410 if (flags.moving)
1411 endMove();
1412
1413 if (windowmenu) windowmenu->hide();
1414
1415 setState(IconicState);
1416
1417 XSelectInput(display, client.window, NoEventMask);
1418 XUnmapWindow(display, client.window);
1419 XSelectInput(display, client.window,
1420 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1421
1422 XUnmapWindow(display, frame.window);
1423 flags.visible = False;
1424 flags.iconic = True;
1425
1426 screen->getWorkspace(workspace_number)->removeWindow(this);
1427
1428 if (flags.transient && client.transient_for &&
1429 !client.transient_for->flags.iconic) {
1430 client.transient_for->iconify();
1431 }
1432 screen->addIcon(this);
1433
1434 if (client.transient && !client.transient->flags.iconic) {
1435 client.transient->iconify();
1436 }
1437 }
1438
1439
1440 void OpenboxWindow::deiconify(bool reassoc, bool raise, bool initial) {
1441 if (flags.iconic || reassoc)
1442 screen->reassociateWindow(this, -1, False);
1443 else if (workspace_number != screen->getCurrentWorkspace()->getWorkspaceID())
1444 return;
1445
1446 setState(NormalState);
1447
1448 XSelectInput(display, client.window, NoEventMask);
1449 XMapWindow(display, client.window);
1450 XSelectInput(display, client.window,
1451 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1452
1453 XMapSubwindows(display, frame.window);
1454 XMapWindow(display, frame.window);
1455
1456 // if we're using the click to place placement type, then immediately
1457 // after the window is mapped, we need to start interactively moving it
1458 if (initial && place_window &&
1459 screen->placementPolicy() == BScreen::ClickMousePlacement) {
1460 int x, y, rx, ry;
1461 Window c, r;
1462 unsigned int m;
1463 XQueryPointer(openbox.getXDisplay(), screen->getRootWindow(),
1464 &r, &c, &rx, &ry, &x, &y, &m);
1465 startMove(rx, ry);
1466 }
1467
1468 if (flags.iconic && screen->focusNew()) setInputFocus();
1469
1470 flags.visible = True;
1471 flags.iconic = False;
1472
1473 if (reassoc && client.transient) client.transient->deiconify(True, False);
1474
1475 if (raise)
1476 screen->getWorkspace(workspace_number)->raiseWindow(this);
1477 }
1478
1479
1480 void OpenboxWindow::close(void) {
1481 XEvent ce;
1482 ce.xclient.type = ClientMessage;
1483 ce.xclient.message_type = openbox.getWMProtocolsAtom();
1484 ce.xclient.display = display;
1485 ce.xclient.window = client.window;
1486 ce.xclient.format = 32;
1487 ce.xclient.data.l[0] = openbox.getWMDeleteAtom();
1488 ce.xclient.data.l[1] = CurrentTime;
1489 ce.xclient.data.l[2] = 0l;
1490 ce.xclient.data.l[3] = 0l;
1491 ce.xclient.data.l[4] = 0l;
1492 XSendEvent(display, client.window, False, NoEventMask, &ce);
1493 }
1494
1495
1496 void OpenboxWindow::withdraw(void) {
1497 if (flags.moving)
1498 endMove();
1499
1500 flags.visible = False;
1501 flags.iconic = False;
1502
1503 XUnmapWindow(display, frame.window);
1504
1505 XSelectInput(display, client.window, NoEventMask);
1506 XUnmapWindow(display, client.window);
1507 XSelectInput(display, client.window,
1508 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1509
1510 if (windowmenu) windowmenu->hide();
1511 }
1512
1513
1514 void OpenboxWindow::maximize(unsigned int button) {
1515 if (flags.moving)
1516 endMove();
1517
1518 // handle case where menu is open then the max button is used instead
1519 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1520
1521 if (flags.maximized) {
1522 flags.maximized = 0;
1523
1524 openbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1525 openbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1526
1527 // when a resize is begun, maximize(0) is called to clear any maximization
1528 // flags currently set. Otherwise it still thinks it is maximized.
1529 // so we do not need to call configure() because resizing will handle it
1530 if (!flags.resizing)
1531 configure(openbox_attrib.premax_x, openbox_attrib.premax_y,
1532 openbox_attrib.premax_w, openbox_attrib.premax_h);
1533
1534 openbox_attrib.premax_x = openbox_attrib.premax_y = 0;
1535 openbox_attrib.premax_w = openbox_attrib.premax_h = 0;
1536
1537 redrawAllButtons();
1538 setState(current_state);
1539 return;
1540 }
1541
1542 openbox_attrib.premax_x = frame.x;
1543 openbox_attrib.premax_y = frame.y;
1544 openbox_attrib.premax_w = frame.width;
1545 openbox_attrib.premax_h = frame.height;
1546
1547 Rect space = screen->availableArea();
1548 unsigned int dw = space.w(),
1549 dh = space.h();
1550 dw -= frame.border_w * 2;
1551 dw -= frame.mwm_border_w * 2;
1552 dw -= client.base_width;
1553
1554 dh -= frame.border_w * 2;
1555 dh -= frame.mwm_border_w * 2;
1556 dh -= ((frame.handle_h + frame.border_w) * decorations.handle);
1557 dh -= client.base_height;
1558 dh -= frame.y_border;
1559
1560 if (dw < client.min_width) dw = client.min_width;
1561 if (dh < client.min_height) dh = client.min_height;
1562 if (dw > client.max_width) dw = client.max_width;
1563 if (dh > client.max_height) dh = client.max_height;
1564
1565 dw -= (dw % client.width_inc);
1566 dw += client.base_width;
1567 dw += frame.mwm_border_w * 2;
1568
1569 dh -= (dh % client.height_inc);
1570 dh += client.base_height;
1571 dh += frame.y_border;
1572 dh += ((frame.handle_h + frame.border_w) * decorations.handle);
1573 dh += frame.mwm_border_w * 2;
1574
1575 int dx = space.x() + ((space.w() - dw) / 2) - frame.border_w,
1576 dy = space.y() + ((space.h() - dh) / 2) - frame.border_w;
1577
1578 switch(button) {
1579 case 1:
1580 openbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1581 openbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1582 break;
1583
1584 case 2:
1585 openbox_attrib.flags |= AttribMaxVert;
1586 openbox_attrib.attrib |= AttribMaxVert;
1587
1588 dw = frame.width;
1589 dx = frame.x;
1590 break;
1591
1592 case 3:
1593 openbox_attrib.flags |= AttribMaxHoriz;
1594 openbox_attrib.attrib |= AttribMaxHoriz;
1595
1596 dh = frame.height;
1597 dy = frame.y;
1598 break;
1599 }
1600
1601 if (flags.shaded) {
1602 openbox_attrib.flags ^= AttribShaded;
1603 openbox_attrib.attrib ^= AttribShaded;
1604 flags.shaded = False;
1605 }
1606
1607 flags.maximized = button;
1608
1609 configure(dx, dy, dw, dh);
1610 screen->getWorkspace(workspace_number)->raiseWindow(this);
1611 redrawAllButtons();
1612 setState(current_state);
1613 }
1614
1615
1616 void OpenboxWindow::setWorkspace(int n) {
1617 ASSERT(n < screen->getWorkspaceCount());
1618 workspace_number = n;
1619
1620 openbox_attrib.flags |= AttribWorkspace;
1621 openbox_attrib.workspace = workspace_number;
1622 }
1623
1624
1625 void OpenboxWindow::shade(void) {
1626 if (!decorations.titlebar)
1627 return;
1628
1629 if (flags.shaded) {
1630 XResizeWindow(display, frame.window, frame.width, frame.height);
1631 flags.shaded = False;
1632 openbox_attrib.flags ^= AttribShaded;
1633 openbox_attrib.attrib ^= AttribShaded;
1634
1635 setState(NormalState);
1636 } else {
1637 XResizeWindow(display, frame.window, frame.width, frame.title_h);
1638 flags.shaded = True;
1639 openbox_attrib.flags |= AttribShaded;
1640 openbox_attrib.attrib |= AttribShaded;
1641
1642 setState(IconicState);
1643 }
1644 }
1645
1646
1647 void OpenboxWindow::stick(void) {
1648 if (flags.stuck) {
1649 openbox_attrib.flags ^= AttribOmnipresent;
1650 openbox_attrib.attrib ^= AttribOmnipresent;
1651
1652 flags.stuck = False;
1653
1654 if (! flags.iconic)
1655 screen->reassociateWindow(this, -1, True);
1656
1657 setState(current_state);
1658 } else {
1659 flags.stuck = True;
1660
1661 openbox_attrib.flags |= AttribOmnipresent;
1662 openbox_attrib.attrib |= AttribOmnipresent;
1663
1664 setState(current_state);
1665 }
1666 }
1667
1668
1669 void OpenboxWindow::setFocusFlag(Bool focus) {
1670 flags.focused = focus;
1671
1672 if (decorations.titlebar) {
1673 if (flags.focused) {
1674 if (frame.ftitle)
1675 XSetWindowBackgroundPixmap(display, frame.title, frame.ftitle);
1676 else
1677 XSetWindowBackground(display, frame.title, frame.ftitle_pixel);
1678 } else {
1679 if (frame.utitle)
1680 XSetWindowBackgroundPixmap(display, frame.title, frame.utitle);
1681 else
1682 XSetWindowBackground(display, frame.title, frame.utitle_pixel);
1683 }
1684 XClearWindow(display, frame.title);
1685
1686 redrawLabel();
1687 redrawAllButtons();
1688 }
1689
1690 if (decorations.handle) {
1691 if (flags.focused) {
1692 if (frame.fhandle)
1693 XSetWindowBackgroundPixmap(display, frame.handle, frame.fhandle);
1694 else
1695 XSetWindowBackground(display, frame.handle, frame.fhandle_pixel);
1696
1697 if (frame.fgrip) {
1698 XSetWindowBackgroundPixmap(display, frame.right_grip, frame.fgrip);
1699 XSetWindowBackgroundPixmap(display, frame.left_grip, frame.fgrip);
1700 } else {
1701 XSetWindowBackground(display, frame.right_grip, frame.fgrip_pixel);
1702 XSetWindowBackground(display, frame.left_grip, frame.fgrip_pixel);
1703 }
1704 } else {
1705 if (frame.uhandle)
1706 XSetWindowBackgroundPixmap(display, frame.handle, frame.uhandle);
1707 else
1708 XSetWindowBackground(display, frame.handle, frame.uhandle_pixel);
1709
1710 if (frame.ugrip) {
1711 XSetWindowBackgroundPixmap(display, frame.right_grip, frame.ugrip);
1712 XSetWindowBackgroundPixmap(display, frame.left_grip, frame.ugrip);
1713 } else {
1714 XSetWindowBackground(display, frame.right_grip, frame.ugrip_pixel);
1715 XSetWindowBackground(display, frame.left_grip, frame.ugrip_pixel);
1716 }
1717 }
1718 XClearWindow(display, frame.handle);
1719 XClearWindow(display, frame.right_grip);
1720 XClearWindow(display, frame.left_grip);
1721 }
1722
1723 if (decorations.border) {
1724 if (flags.focused)
1725 XSetWindowBorder(display, frame.plate, frame.fborder_pixel);
1726 else
1727 XSetWindowBorder(display, frame.plate, frame.uborder_pixel);
1728 }
1729
1730 if (screen->sloppyFocus() && screen->autoRaise() && timer->isTiming())
1731 timer->stop();
1732
1733 }
1734
1735
1736 void OpenboxWindow::installColormap(Bool install) {
1737 openbox.grab();
1738 if (! validateClient()) return;
1739
1740 int i = 0, ncmap = 0;
1741 Colormap *cmaps = XListInstalledColormaps(display, client.window, &ncmap);
1742 XWindowAttributes wattrib;
1743 if (cmaps) {
1744 if (XGetWindowAttributes(display, client.window, &wattrib)) {
1745 if (install) {
1746 // install the window's colormap
1747 for (i = 0; i < ncmap; i++) {
1748 if (*(cmaps + i) == wattrib.colormap)
1749 // this window is using an installed color map... do not install
1750 install = False;
1751 }
1752 // otherwise, install the window's colormap
1753 if (install)
1754 XInstallColormap(display, wattrib.colormap);
1755 } else {
1756 // uninstall the window's colormap
1757 for (i = 0; i < ncmap; i++) {
1758 if (*(cmaps + i) == wattrib.colormap)
1759 // we found the colormap to uninstall
1760 XUninstallColormap(display, wattrib.colormap);
1761 }
1762 }
1763 }
1764
1765 XFree(cmaps);
1766 }
1767
1768 openbox.ungrab();
1769 }
1770
1771
1772 void OpenboxWindow::setState(unsigned long new_state) {
1773 current_state = new_state;
1774
1775 unsigned long state[2];
1776 state[0] = (unsigned long) current_state;
1777 state[1] = (unsigned long) None;
1778 XChangeProperty(display, client.window, openbox.getWMStateAtom(),
1779 openbox.getWMStateAtom(), 32, PropModeReplace,
1780 (unsigned char *) state, 2);
1781
1782 XChangeProperty(display, client.window,
1783 openbox.getOpenboxAttributesAtom(),
1784 openbox.getOpenboxAttributesAtom(), 32, PropModeReplace,
1785 (unsigned char *) &openbox_attrib,
1786 PropOpenboxAttributesElements);
1787 }
1788
1789
1790 Bool OpenboxWindow::getState(void) {
1791 current_state = 0;
1792
1793 Atom atom_return;
1794 Bool ret = False;
1795 int foo;
1796 unsigned long *state, ulfoo, nitems;
1797
1798 if ((XGetWindowProperty(display, client.window, openbox.getWMStateAtom(),
1799 0l, 2l, False, openbox.getWMStateAtom(),
1800 &atom_return, &foo, &nitems, &ulfoo,
1801 (unsigned char **) &state) != Success) ||
1802 (! state)) {
1803 openbox.ungrab();
1804 return False;
1805 }
1806
1807 if (nitems >= 1) {
1808 current_state = (unsigned long) state[0];
1809
1810 ret = True;
1811 }
1812
1813 XFree((void *) state);
1814
1815 return ret;
1816 }
1817
1818
1819 void OpenboxWindow::setGravityOffsets(void) {
1820 // x coordinates for each gravity type
1821 const int x_west = client.x;
1822 const int x_east = client.x + client.width - frame.width;
1823 const int x_center = client.x + client.width - frame.width/2;
1824 // y coordinates for each gravity type
1825 const int y_north = client.y;
1826 const int y_south = client.y + client.height - frame.height;
1827 const int y_center = client.y + client.height - frame.height/2;
1828
1829 switch (client.win_gravity) {
1830 case NorthWestGravity:
1831 default:
1832 frame.x = x_west;
1833 frame.y = y_north;
1834 break;
1835 case NorthGravity:
1836 frame.x = x_center;
1837 frame.y = y_north;
1838 break;
1839 case NorthEastGravity:
1840 frame.x = x_east;
1841 frame.y = y_north;
1842 break;
1843 case SouthWestGravity:
1844 frame.x = x_west;
1845 frame.y = y_south;
1846 break;
1847 case SouthGravity:
1848 frame.x = x_center;
1849 frame.y = y_south;
1850 break;
1851 case SouthEastGravity:
1852 frame.x = x_east;
1853 frame.y = y_south;
1854 break;
1855 case WestGravity:
1856 frame.x = x_west;
1857 frame.y = y_center;
1858 break;
1859 case EastGravity:
1860 frame.x = x_east;
1861 frame.y = y_center;
1862 break;
1863 case CenterGravity:
1864 frame.x = x_center;
1865 frame.y = y_center;
1866 break;
1867 case ForgetGravity:
1868 case StaticGravity:
1869 frame.x = client.x - frame.mwm_border_w + frame.border_w;
1870 frame.y = client.y - frame.y_border - frame.mwm_border_w - frame.border_w;
1871 break;
1872 }
1873 }
1874
1875
1876 void OpenboxWindow::restoreAttributes(void) {
1877 if (! getState()) current_state = NormalState;
1878
1879 Atom atom_return;
1880 int foo;
1881 unsigned long ulfoo, nitems;
1882
1883 OpenboxAttributes *net;
1884 int ret = XGetWindowProperty(display, client.window,
1885 openbox.getOpenboxAttributesAtom(), 0l,
1886 PropOpenboxAttributesElements, False,
1887 openbox.getOpenboxAttributesAtom(),
1888 &atom_return, &foo, &nitems, &ulfoo,
1889 (unsigned char **) &net);
1890 if (ret != Success || !net || nitems != PropOpenboxAttributesElements)
1891 return;
1892
1893 openbox_attrib.flags = net->flags;
1894 openbox_attrib.attrib = net->attrib;
1895 openbox_attrib.decoration = net->decoration;
1896 openbox_attrib.workspace = net->workspace;
1897 openbox_attrib.stack = net->stack;
1898 openbox_attrib.premax_x = net->premax_x;
1899 openbox_attrib.premax_y = net->premax_y;
1900 openbox_attrib.premax_w = net->premax_w;
1901 openbox_attrib.premax_h = net->premax_h;
1902
1903 XFree((void *) net);
1904
1905 if (openbox_attrib.flags & AttribShaded &&
1906 openbox_attrib.attrib & AttribShaded) {
1907 int save_state =
1908 ((current_state == IconicState) ? NormalState : current_state);
1909
1910 flags.shaded = False;
1911 shade();
1912
1913 current_state = save_state;
1914 }
1915
1916 if (((int) openbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
1917 ((int) openbox_attrib.workspace < screen->getWorkspaceCount())) {
1918 screen->reassociateWindow(this, openbox_attrib.workspace, True);
1919
1920 if (current_state == NormalState) current_state = WithdrawnState;
1921 } else if (current_state == WithdrawnState) {
1922 current_state = NormalState;
1923 }
1924
1925 if (openbox_attrib.flags & AttribOmnipresent &&
1926 openbox_attrib.attrib & AttribOmnipresent) {
1927 flags.stuck = False;
1928 stick();
1929
1930 current_state = NormalState;
1931 }
1932
1933 if ((openbox_attrib.flags & AttribMaxHoriz) ||
1934 (openbox_attrib.flags & AttribMaxVert)) {
1935 int x = openbox_attrib.premax_x, y = openbox_attrib.premax_y;
1936 unsigned int w = openbox_attrib.premax_w, h = openbox_attrib.premax_h;
1937 flags.maximized = 0;
1938
1939 unsigned int m = False;
1940 if ((openbox_attrib.flags & AttribMaxHoriz) &&
1941 (openbox_attrib.flags & AttribMaxVert))
1942 m = (openbox_attrib.attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1943 else if (openbox_attrib.flags & AttribMaxVert)
1944 m = (openbox_attrib.attrib & AttribMaxVert) ? 2 : 0;
1945 else if (openbox_attrib.flags & AttribMaxHoriz)
1946 m = (openbox_attrib.attrib & AttribMaxHoriz) ? 3 : 0;
1947
1948 if (m) maximize(m);
1949
1950 openbox_attrib.premax_x = x;
1951 openbox_attrib.premax_y = y;
1952 openbox_attrib.premax_w = w;
1953 openbox_attrib.premax_h = h;
1954 }
1955
1956 setState(current_state);
1957 }
1958
1959
1960 /*
1961 * The reverse of the setGravityOffsets function. Uses the frame window's
1962 * position to find the window's reference point.
1963 */
1964 void OpenboxWindow::restoreGravity(void) {
1965 // x coordinates for each gravity type
1966 const int x_west = frame.x;
1967 const int x_east = frame.x + frame.width - client.width;
1968 const int x_center = frame.x + (frame.width/2) - client.width;
1969 // y coordinates for each gravity type
1970 const int y_north = frame.y;
1971 const int y_south = frame.y + frame.height - client.height;
1972 const int y_center = frame.y + (frame.height/2) - client.height;
1973
1974 switch(client.win_gravity) {
1975 default:
1976 case NorthWestGravity:
1977 client.x = x_west;
1978 client.y = y_north;
1979 break;
1980 case NorthGravity:
1981 client.x = x_center;
1982 client.y = y_north;
1983 break;
1984 case NorthEastGravity:
1985 client.x = x_east;
1986 client.y = y_north;
1987 break;
1988 case SouthWestGravity:
1989 client.x = x_west;
1990 client.y = y_south;
1991 break;
1992 case SouthGravity:
1993 client.x = x_center;
1994 client.y = y_south;
1995 break;
1996 case SouthEastGravity:
1997 client.x = x_east;
1998 client.y = y_south;
1999 break;
2000 case WestGravity:
2001 client.x = x_west;
2002 client.y = y_center;
2003 break;
2004 case EastGravity:
2005 client.x = x_east;
2006 client.y = y_center;
2007 break;
2008 case CenterGravity:
2009 client.x = x_center;
2010 client.y = y_center;
2011 break;
2012 case ForgetGravity:
2013 case StaticGravity:
2014 client.x = frame.x + frame.mwm_border_w + frame.border_w;
2015 client.y = frame.y + frame.y_border + frame.mwm_border_w +
2016 frame.border_w;
2017 break;
2018 }
2019 }
2020
2021
2022 void OpenboxWindow::redrawLabel(void) {
2023 int dx = frame.bevel_w * 2, dlen = client.title_len;
2024 unsigned int l = client.title_text_w;
2025
2026 if (flags.focused) {
2027 if (frame.flabel)
2028 XSetWindowBackgroundPixmap(display, frame.label, frame.flabel);
2029 else
2030 XSetWindowBackground(display, frame.label, frame.flabel_pixel);
2031 } else {
2032 if (frame.ulabel)
2033 XSetWindowBackgroundPixmap(display, frame.label, frame.ulabel);
2034 else
2035 XSetWindowBackground(display, frame.label, frame.ulabel_pixel);
2036 }
2037 XClearWindow(display, frame.label);
2038
2039 if (client.title_text_w > frame.label_w) {
2040 for (; dlen >= 0; dlen--) {
2041 if (i18n->multibyte()) {
2042 XRectangle ink, logical;
2043 XmbTextExtents(screen->getWindowStyle()->fontset, client.title, dlen,
2044 &ink, &logical);
2045 l = logical.width;
2046 } else {
2047 l = XTextWidth(screen->getWindowStyle()->font, client.title, dlen);
2048 }
2049 l += (frame.bevel_w * 4);
2050
2051 if (l < frame.label_w)
2052 break;
2053 }
2054 }
2055
2056 switch (screen->getWindowStyle()->justify) {
2057 case BScreen::RightJustify:
2058 dx += frame.label_w - l;
2059 break;
2060
2061 case BScreen::CenterJustify:
2062 dx += (frame.label_w - l) / 2;
2063 break;
2064 }
2065
2066 WindowStyle *style = screen->getWindowStyle();
2067 GC text_gc = (flags.focused) ? style->l_text_focus_gc :
2068 style->l_text_unfocus_gc;
2069 if (i18n->multibyte())
2070 XmbDrawString(display, frame.label, style->fontset, text_gc, dx,
2071 (1 - style->fontset_extents->max_ink_extent.y),
2072 client.title, dlen);
2073 else
2074 XDrawString(display, frame.label, text_gc, dx,
2075 (style->font->ascent + 1), client.title, dlen);
2076 }
2077
2078
2079 void OpenboxWindow::redrawAllButtons(void) {
2080 if (frame.iconify_button) redrawIconifyButton(False);
2081 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2082 if (frame.close_button) redrawCloseButton(False);
2083 }
2084
2085
2086 void OpenboxWindow::redrawIconifyButton(Bool pressed) {
2087 if (! pressed) {
2088 if (flags.focused) {
2089 if (frame.fbutton)
2090 XSetWindowBackgroundPixmap(display, frame.iconify_button,
2091 frame.fbutton);
2092 else
2093 XSetWindowBackground(display, frame.iconify_button,
2094 frame.fbutton_pixel);
2095 } else {
2096 if (frame.ubutton)
2097 XSetWindowBackgroundPixmap(display, frame.iconify_button,
2098 frame.ubutton);
2099 else
2100 XSetWindowBackground(display, frame.iconify_button,
2101 frame.ubutton_pixel);
2102 }
2103 } else {
2104 if (frame.pbutton)
2105 XSetWindowBackgroundPixmap(display, frame.iconify_button, frame.pbutton);
2106 else
2107 XSetWindowBackground(display, frame.iconify_button, frame.pbutton_pixel);
2108 }
2109 XClearWindow(display, frame.iconify_button);
2110
2111 XDrawRectangle(display, frame.iconify_button,
2112 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2113 screen->getWindowStyle()->b_pic_unfocus_gc),
2114 2, (frame.button_h - 5), (frame.button_w - 5), 2);
2115 }
2116
2117
2118 void OpenboxWindow::redrawMaximizeButton(Bool pressed) {
2119 if (! pressed) {
2120 if (flags.focused) {
2121 if (frame.fbutton)
2122 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2123 frame.fbutton);
2124 else
2125 XSetWindowBackground(display, frame.maximize_button,
2126 frame.fbutton_pixel);
2127 } else {
2128 if (frame.ubutton)
2129 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2130 frame.ubutton);
2131 else
2132 XSetWindowBackground(display, frame.maximize_button,
2133 frame.ubutton_pixel);
2134 }
2135 } else {
2136 if (frame.pbutton)
2137 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2138 frame.pbutton);
2139 else
2140 XSetWindowBackground(display, frame.maximize_button,
2141 frame.pbutton_pixel);
2142 }
2143 XClearWindow(display, frame.maximize_button);
2144
2145 XDrawRectangle(display, frame.maximize_button,
2146 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2147 screen->getWindowStyle()->b_pic_unfocus_gc),
2148 2, 2, (frame.button_w - 5), (frame.button_h - 5));
2149 XDrawLine(display, frame.maximize_button,
2150 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2151 screen->getWindowStyle()->b_pic_unfocus_gc),
2152 2, 3, (frame.button_w - 3), 3);
2153 }
2154
2155
2156 void OpenboxWindow::redrawCloseButton(Bool pressed) {
2157 if (! pressed) {
2158 if (flags.focused) {
2159 if (frame.fbutton)
2160 XSetWindowBackgroundPixmap(display, frame.close_button,
2161 frame.fbutton);
2162 else
2163 XSetWindowBackground(display, frame.close_button,
2164 frame.fbutton_pixel);
2165 } else {
2166 if (frame.ubutton)
2167 XSetWindowBackgroundPixmap(display, frame.close_button,
2168 frame.ubutton);
2169 else
2170 XSetWindowBackground(display, frame.close_button,
2171 frame.ubutton_pixel);
2172 }
2173 } else {
2174 if (frame.pbutton)
2175 XSetWindowBackgroundPixmap(display, frame.close_button, frame.pbutton);
2176 else
2177 XSetWindowBackground(display, frame.close_button, frame.pbutton_pixel);
2178 }
2179 XClearWindow(display, frame.close_button);
2180
2181 XDrawLine(display, frame.close_button,
2182 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2183 screen->getWindowStyle()->b_pic_unfocus_gc), 2, 2,
2184 (frame.button_w - 3), (frame.button_h - 3));
2185 XDrawLine(display, frame.close_button,
2186 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2187 screen->getWindowStyle()->b_pic_unfocus_gc), 2,
2188 (frame.button_h - 3),
2189 (frame.button_w - 3), 2);
2190 }
2191
2192
2193 void OpenboxWindow::mapRequestEvent(XMapRequestEvent *re) {
2194 if (re->window == client.window) {
2195 #ifdef DEBUG
2196 fprintf(stderr, i18n->getMessage(WindowSet, WindowMapRequest,
2197 "OpenboxWindow::mapRequestEvent() for 0x%lx\n"),
2198 client.window);
2199 #endif // DEBUG
2200
2201 openbox.grab();
2202 if (! validateClient()) return;
2203
2204 Bool get_state_ret = getState();
2205 if (! (get_state_ret && openbox.isStartup())) {
2206 if ((client.wm_hint_flags & StateHint) &&
2207 (! (current_state == NormalState || current_state == IconicState)))
2208 current_state = client.initial_state;
2209 else
2210 current_state = NormalState;
2211 } else if (flags.iconic) {
2212 current_state = NormalState;
2213 }
2214
2215 switch (current_state) {
2216 case IconicState:
2217 iconify();
2218 break;
2219
2220 case WithdrawnState:
2221 withdraw();
2222 break;
2223
2224 case NormalState:
2225 case InactiveState:
2226 case ZoomState:
2227 default:
2228 deiconify(False, True, True); // specify that we're initializing the
2229 // window
2230 break;
2231 }
2232
2233 openbox.ungrab();
2234 }
2235 }
2236
2237
2238 void OpenboxWindow::mapNotifyEvent(XMapEvent *ne) {
2239 if ((ne->window == client.window) && (! ne->override_redirect)
2240 && (flags.visible)) {
2241 openbox.grab();
2242 if (! validateClient()) return;
2243
2244 if (decorations.titlebar) positionButtons();
2245
2246 setState(NormalState);
2247
2248 redrawAllButtons();
2249
2250 if (flags.transient || screen->focusNew())
2251 setInputFocus();
2252 else
2253 setFocusFlag(False);
2254
2255 flags.visible = True;
2256 flags.iconic = False;
2257
2258 openbox.ungrab();
2259 }
2260 }
2261
2262
2263 void OpenboxWindow::unmapNotifyEvent(XUnmapEvent *ue) {
2264 if (ue->window == client.window) {
2265 #ifdef DEBUG
2266 fprintf(stderr, i18n->getMessage(WindowSet, WindowUnmapNotify,
2267 "OpenboxWindow::unmapNotifyEvent() for 0x%lx\n"),
2268 client.window);
2269 #endif // DEBUG
2270
2271 openbox.grab();
2272 if (! validateClient()) return;
2273
2274 if (flags.moving)
2275 endMove();
2276
2277 XChangeSaveSet(display, client.window, SetModeDelete);
2278 XSelectInput(display, client.window, NoEventMask);
2279
2280 XDeleteProperty(display, client.window, openbox.getWMStateAtom());
2281 XDeleteProperty(display, client.window,
2282 openbox.getOpenboxAttributesAtom());
2283
2284 XUnmapWindow(display, frame.window);
2285 XUnmapWindow(display, client.window);
2286
2287 XEvent dummy;
2288 if (! XCheckTypedWindowEvent(display, client.window, ReparentNotify,
2289 &dummy)) {
2290 #ifdef DEBUG
2291 fprintf(stderr, i18n->getMessage(WindowSet, WindowUnmapNotifyReparent,
2292 "OpenboxWindow::unmapNotifyEvent(): reparent 0x%lx to "
2293 "root.\n"), client.window);
2294 #endif // DEBUG
2295
2296 restoreGravity();
2297 XReparentWindow(display, client.window, screen->getRootWindow(),
2298 client.x, client.y);
2299 }
2300
2301 XFlush(display);
2302
2303 openbox.ungrab();
2304
2305 delete this;
2306 }
2307 }
2308
2309
2310 void OpenboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) {
2311 if (de->window == client.window) {
2312 if (flags.moving)
2313 endMove();
2314 XUnmapWindow(display, frame.window);
2315
2316 delete this;
2317 }
2318 }
2319
2320
2321 void OpenboxWindow::propertyNotifyEvent(Atom atom) {
2322 openbox.grab();
2323 if (! validateClient()) return;
2324
2325 switch(atom) {
2326 case XA_WM_CLASS:
2327 case XA_WM_CLIENT_MACHINE:
2328 case XA_WM_COMMAND:
2329 break;
2330
2331 case XA_WM_TRANSIENT_FOR:
2332 // determine if this is a transient window
2333 Window win;
2334 if (XGetTransientForHint(display, client.window, &win)) {
2335 if (win && (win != client.window)) {
2336 if ((client.transient_for = openbox.searchWindow(win))) {
2337 client.transient_for->client.transient = this;
2338 flags.stuck = client.transient_for->flags.stuck;
2339 flags.transient = True;
2340 } else if (win == client.window_group) {
2341 //jr This doesn't look quite right...
2342 if ((client.transient_for = openbox.searchGroup(win, this))) {
2343 client.transient_for->client.transient = this;
2344 flags.stuck = client.transient_for->flags.stuck;
2345 flags.transient = True;
2346 }
2347 }
2348 }
2349
2350 if (win == screen->getRootWindow()) flags.modal = True;
2351 }
2352
2353 // adjust the window decorations based on transience
2354 if (flags.transient)
2355 decorations.maximize = decorations.handle = functions.maximize = False;
2356
2357 reconfigure();
2358
2359 break;
2360
2361 case XA_WM_HINTS:
2362 getWMHints();
2363 break;
2364
2365 case XA_WM_ICON_NAME:
2366 getWMIconName();
2367 if (flags.iconic) screen->iconUpdate();
2368 break;
2369
2370 case XA_WM_NAME:
2371 getWMName();
2372
2373 if (decorations.titlebar)
2374 redrawLabel();
2375
2376 if (! flags.iconic)
2377 screen->getWorkspace(workspace_number)->update();
2378
2379 break;
2380
2381 case XA_WM_NORMAL_HINTS: {
2382 getWMNormalHints();
2383
2384 if ((client.normal_hint_flags & PMinSize) &&
2385 (client.normal_hint_flags & PMaxSize)) {
2386 if (client.max_width <= client.min_width &&
2387 client.max_height <= client.min_height)
2388 decorations.maximize = decorations.handle =
2389 functions.resize = functions.maximize = False;
2390 else
2391 decorations.maximize = decorations.handle =
2392 functions.resize = functions.maximize = True;
2393 }
2394
2395 int x = frame.x, y = frame.y;
2396 unsigned int w = frame.width, h = frame.height;
2397
2398 upsize();
2399
2400 if ((x != frame.x) || (y != frame.y) ||
2401 (w != frame.width) || (h != frame.height))
2402 reconfigure();
2403
2404 break;
2405 }
2406
2407 default:
2408 if (atom == openbox.getWMProtocolsAtom()) {
2409 getWMProtocols();
2410
2411 if (decorations.close && (! frame.close_button)) {
2412 createCloseButton();
2413 if (decorations.titlebar) positionButtons(True);
2414 if (windowmenu) windowmenu->reconfigure();
2415 }
2416 }
2417
2418 break;
2419 }
2420
2421 openbox.ungrab();
2422 }
2423
2424
2425 void OpenboxWindow::exposeEvent(XExposeEvent *ee) {
2426 if (frame.label == ee->window && decorations.titlebar)
2427 redrawLabel();
2428 else if (frame.close_button == ee->window)
2429 redrawCloseButton(False);
2430 else if (frame.maximize_button == ee->window)
2431 redrawMaximizeButton(flags.maximized);
2432 else if (frame.iconify_button == ee->window)
2433 redrawIconifyButton(False);
2434 }
2435
2436
2437 void OpenboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) {
2438 if (cr->window == client.window) {
2439 openbox.grab();
2440 if (! validateClient()) return;
2441
2442 int cx = frame.x, cy = frame.y;
2443 unsigned int cw = frame.width, ch = frame.height;
2444
2445 if (cr->value_mask & CWBorderWidth)
2446 client.old_bw = cr->border_width;
2447
2448 if (cr->value_mask & CWX)
2449 cx = cr->x - frame.mwm_border_w - frame.border_w;
2450
2451 if (cr->value_mask & CWY)
2452 cy = cr->y - frame.y_border - frame.mwm_border_w -
2453 frame.border_w;
2454
2455 if (cr->value_mask & CWWidth)
2456 cw = cr->width + (frame.mwm_border_w * 2);
2457
2458 if (cr->value_mask & CWHeight)
2459 ch = cr->height + frame.y_border + (frame.mwm_border_w * 2) +
2460 (frame.border_w * decorations.handle) + frame.handle_h;
2461
2462 if (frame.x != cx || frame.y != cy ||
2463 frame.width != cw || frame.height != ch)
2464 configure(cx, cy, cw, ch);
2465
2466 if (cr->value_mask & CWStackMode) {
2467 switch (cr->detail) {
2468 case Above:
2469 case TopIf:
2470 default:
2471 if (flags.iconic) deiconify();
2472 screen->getWorkspace(workspace_number)->raiseWindow(this);
2473 break;
2474
2475 case Below:
2476 case BottomIf:
2477 if (flags.iconic) deiconify();
2478 screen->getWorkspace(workspace_number)->lowerWindow(this);
2479 break;
2480 }
2481 }
2482
2483 openbox.ungrab();
2484 }
2485 }
2486
2487
2488 void OpenboxWindow::buttonPressEvent(XButtonEvent *be) {
2489 openbox.grab();
2490 if (! validateClient())
2491 return;
2492
2493 int stack_change = 1; // < 0 means to lower the window
2494 // > 0 means to raise the window
2495 // 0 means to leave it where it is
2496
2497 // alt + left/right click begins interactively moving/resizing the window
2498 // when the mouse is moved
2499 if (be->state == Mod1Mask && (be->button == 1 || be->button == 3)) {
2500 if (be->button == 3) {
2501 if (screen->getWindowZones() == 4 &&
2502 be->y < (signed) frame.height / 2) {
2503 resize_zone = ZoneTop;
2504 } else {
2505 resize_zone = ZoneBottom;
2506 }
2507 if (screen->getWindowZones() >= 2 &&
2508 be->x < (signed) frame.width / 2) {
2509 resize_zone |= ZoneLeft;
2510 } else {
2511 resize_zone |= ZoneRight;
2512 }
2513 }
2514 // control + left click on the titlebar shades the window
2515 } else if (be->state == ControlMask && be->button == 1) {
2516 if (be->window == frame.title ||
2517 be->window == frame.label)
2518 shade();
2519 // left click
2520 } else if (be->state == 0 && be->button == 1) {
2521 if (windowmenu && windowmenu->isVisible())
2522 windowmenu->hide();
2523
2524 if (be->window == frame.maximize_button) {
2525 redrawMaximizeButton(True);
2526 } else if (be->window == frame.iconify_button) {
2527 redrawIconifyButton(True);
2528 } else if (be->window == frame.close_button) {
2529 redrawCloseButton(True);
2530 } else if (be->window == frame.plate) {
2531 XAllowEvents(display, ReplayPointer, be->time);
2532 } else if (be->window == frame.title ||
2533 be->window == frame.label) {
2534 // shade the window when the titlebar is double clicked
2535 if ( (be->time - lastButtonPressTime) <=
2536 openbox.getDoubleClickInterval()) {
2537 lastButtonPressTime = 0;
2538 shade();
2539 } else {
2540 lastButtonPressTime = be->time;
2541 }
2542 // clicking and dragging on the titlebar moves the window, so on a click
2543 // we need to save the coords of the click in case the user drags
2544 frame.grab_x = be->x_root - frame.x - frame.border_w;
2545 frame.grab_y = be->y_root - frame.y - frame.border_w;
2546 } else if (be->window == frame.handle ||
2547 be->window == frame.left_grip ||
2548 be->window == frame.right_grip ||
2549 be->window == frame.window) {
2550 // clicking and dragging on the window's frame moves the window, so on a
2551 // click we need to save the coords of the click in case the user drags
2552 frame.grab_x = be->x_root - frame.x - frame.border_w;
2553 frame.grab_y = be->y_root - frame.y - frame.border_w;
2554 if (be->window == frame.left_grip)
2555 resize_zone = ZoneBottom | ZoneLeft;
2556 else if (be->window == frame.right_grip)
2557 resize_zone = ZoneBottom | ZoneRight;
2558 }
2559 // middle click
2560 } else if (be->state == 0 && be->button == 2) {
2561 if (be->window == frame.maximize_button) {
2562 redrawMaximizeButton(True);
2563 // a middle click anywhere on the window's frame except for on the buttons
2564 // will lower the window
2565 } else if (! (be->window == frame.iconify_button ||
2566 be->window == frame.close_button) ) {
2567 stack_change = -1;
2568 }
2569 // right click
2570 } else if (be->state == 0 && be->button == 3) {
2571 if (be->window == frame.maximize_button) {
2572 redrawMaximizeButton(True);
2573 // a right click on the window's frame will show or hide the window's
2574 // windowmenu
2575 } else if (be->window == frame.title ||
2576 be->window == frame.label ||
2577 be->window == frame.handle ||
2578 be->window == frame.window) {
2579 int mx, my;
2580 if (windowmenu) {
2581 if (windowmenu->isVisible()) {
2582 windowmenu->hide();
2583 } else {
2584 // get the coords for the menu
2585 mx = be->x_root - windowmenu->getWidth() / 2;
2586 if (be->window == frame.title || be->window == frame.label) {
2587 my = frame.y + frame.title_h;
2588 } else if (be->window == frame.handle) {
2589 my = frame.y + frame.y_handle - windowmenu->getHeight();
2590 } else { // (be->window == frame.window)
2591 if (be->y <= (signed) frame.bevel_w) {
2592 my = frame.y + frame.y_border;
2593 } else {
2594 my = be->y_root - (windowmenu->getHeight() / 2);
2595 }
2596 }
2597
2598 if (mx > (signed) (frame.x + frame.width -
2599 windowmenu->getWidth())) {
2600 mx = frame.x + frame.width - windowmenu->getWidth();
2601 } else if (mx < frame.x) {
2602 mx = frame.x;
2603 }
2604
2605 if (my > (signed) (frame.y + frame.y_handle -
2606 windowmenu->getHeight())) {
2607 my = frame.y + frame.y_handle - windowmenu->getHeight();
2608 } else if (my < (signed) (frame.y +
2609 ((decorations.titlebar) ? frame.title_h : frame.y_border))) {
2610 my = frame.y +
2611 ((decorations.titlebar) ? frame.title_h : frame.y_border);
2612 }
2613
2614 windowmenu->move(mx, my);
2615 windowmenu->show();
2616 XRaiseWindow(display, windowmenu->getWindowID());
2617 XRaiseWindow(display, windowmenu->getSendToMenu()->getWindowID());
2618 stack_change = 0; // dont raise the window overtop of the menu
2619 }
2620 }
2621 }
2622 // mouse wheel up
2623 } else if (be->state == 0 && be->button == 4) {
2624 if ((be->window == frame.label ||
2625 be->window == frame.title) &&
2626 !flags.shaded)
2627 shade();
2628 // mouse wheel down
2629 } else if (be->state == 0 && be->button == 5) {
2630 if ((be->window == frame.label ||
2631 be->window == frame.title) &&
2632 flags.shaded)
2633 shade();
2634 }
2635
2636 if (! (flags.focused || screen->sloppyFocus()) ) {
2637 setInputFocus(); // any click focus' the window in 'click to focus'
2638 }
2639 if (stack_change < 0) {
2640 screen->getWorkspace(workspace_number)->lowerWindow(this);
2641 } else if (stack_change > 0) {
2642 screen->getWorkspace(workspace_number)->raiseWindow(this);
2643 }
2644
2645 openbox.ungrab();
2646 }
2647
2648
2649 void OpenboxWindow::buttonReleaseEvent(XButtonEvent *re) {
2650 openbox.grab();
2651 if (! validateClient())
2652 return;
2653
2654 // alt + middle button released
2655 if (re->state == (Mod1Mask & Button2Mask) && re->button == 2) {
2656 if (re->window == frame.window) {
2657 XUngrabPointer(display, CurrentTime); // why? i dont know
2658 }
2659 // left button released
2660 } else if (re->button == 1) {
2661 if (re->window == frame.maximize_button) {
2662 if (re->state == Button1Mask && // only the left button was depressed
2663 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2664 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2665 maximize(re->button);
2666 } else {
2667 redrawMaximizeButton(False);
2668 }
2669 } else if (re->window == frame.iconify_button) {
2670 if (re->state == Button1Mask && // only the left button was depressed
2671 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2672 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2673 iconify();
2674 } else {
2675 redrawIconifyButton(False);
2676 }
2677 } else if (re->window == frame.close_button) {
2678 if (re->state == Button1Mask && // only the left button was depressed
2679 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2680 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2681 close();
2682 }
2683 //we should always redraw the close button. some applications
2684 //eg. acroread don't honour the close.
2685 redrawCloseButton(False);
2686 }
2687 // middle button released
2688 } else if (re->button == 2) {
2689 if (re->window == frame.maximize_button) {
2690 if (re->state == Button2Mask && // only the middle button was depressed
2691 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2692 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2693 maximize(re->button);
2694 } else {
2695 redrawMaximizeButton(False);
2696 }
2697 }
2698 // right button released
2699 } else if (re->button == 3) {
2700 if (re->window == frame.maximize_button) {
2701 if (re->state == Button3Mask && // only the right button was depressed
2702 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2703 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2704 maximize(re->button);
2705 } else {
2706 redrawMaximizeButton(False);
2707 }
2708 }
2709 }
2710
2711 // when the window is being interactively moved, a button release stops the
2712 // move where it is
2713 if (flags.moving) {
2714 endMove();
2715 // when the window is being interactively resized, a button release stops the
2716 // resizing
2717 } else if (flags.resizing) {
2718 flags.resizing = False;
2719 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2720 frame.resize_x, frame.resize_y,
2721 frame.resize_w - 1, frame.resize_h - 1);
2722 screen->hideGeometry();
2723 if (resize_zone & ZoneLeft) {
2724 left_fixsize();
2725 } else { // when resizing with "Alt+Button3", the resize is the same as if
2726 // done with the right grip (the right side of the window is what
2727 // moves)
2728 right_fixsize();
2729 }
2730 // unset maximized state when resized after fully maximized
2731 if (flags.maximized == 1) {
2732 maximize(0);
2733 }
2734 configure(frame.resize_x, frame.resize_y,
2735 frame.resize_w - (frame.border_w * 2),
2736 frame.resize_h - (frame.border_w * 2));
2737 openbox.ungrab();
2738 XUngrabPointer(display, CurrentTime);
2739 resize_zone = 0;
2740 }
2741
2742 openbox.ungrab();
2743 }
2744
2745
2746 void OpenboxWindow::startMove(int x, int y) {
2747 ASSERT(!flags.moving);
2748
2749 // make sure only one window is moving at a time
2750 OpenboxWindow *w = openbox.getMaskedWindow();
2751 if (w != (OpenboxWindow *) 0 && w->flags.moving)
2752 w->endMove();
2753
2754 XGrabPointer(display, frame.window, False, PointerMotionMask |
2755 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
2756 None, openbox.getMoveCursor(), CurrentTime);
2757
2758 if (windowmenu && windowmenu->isVisible())
2759 windowmenu->hide();
2760
2761 flags.moving = True;
2762
2763 openbox.maskWindowEvents(client.window, this);
2764
2765 if (! screen->opaqueMove()) {
2766 openbox.grab();
2767
2768 frame.move_x = frame.x;
2769 frame.move_y = frame.y;
2770 frame.resize_w = frame.width + (frame.border_w * 2);
2771 frame.resize_h = ((flags.shaded) ? frame.title_h : frame.height) +
2772 (frame.border_w * 2);
2773
2774 screen->showPosition(frame.x, frame.y);
2775
2776 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2777 frame.move_x, frame.move_y,
2778 frame.resize_w - 1, frame.resize_h - 1);
2779 }
2780 frame.grab_x = x - frame.x - frame.border_w;
2781 frame.grab_y = y - frame.y - frame.border_w;
2782 }
2783
2784
2785 void OpenboxWindow::doMove(int x, int y) {
2786 ASSERT(flags.moving);
2787
2788 int dx = x - frame.grab_x, dy = y - frame.grab_y;
2789
2790 dx -= frame.border_w;
2791 dy -= frame.border_w;
2792
2793 int snap_distance = screen->edgeSnapThreshold();
2794 // width/height of the snapping window
2795 unsigned int snap_w = frame.width + (frame.border_w * 2);
2796 unsigned int snap_h = area().h() + (frame.border_w * 2);
2797 if (snap_distance) {
2798 int drx = screen->size().w() - (dx + snap_w);
2799
2800 if (dx < drx && (dx > 0 && dx < snap_distance) ||
2801 (dx < 0 && dx > -snap_distance) )
2802 dx = 0;
2803 else if ( (drx > 0 && drx < snap_distance) ||
2804 (drx < 0 && drx > -snap_distance) )
2805 dx = screen->size().w() - snap_w;
2806
2807 int dtty, dbby, dty, dby;
2808 switch (screen->getToolbar()->placement()) {
2809 case Toolbar::TopLeft:
2810 case Toolbar::TopCenter:
2811 case Toolbar::TopRight:
2812 dtty = screen->getToolbar()->getExposedHeight() +
2813 frame.border_w;
2814 dbby = screen->size().h();
2815 break;
2816
2817 default:
2818 dtty = 0;
2819 dbby = screen->getToolbar()->area().y();
2820 break;
2821 }
2822
2823 dty = dy - dtty;
2824 dby = dbby - (dy + snap_h);
2825
2826 if ( (dy > 0 && dty < snap_distance) ||
2827 (dy < 0 && dty > -snap_distance) )
2828 dy = dtty;
2829 else if ( (dby > 0 && dby < snap_distance) ||
2830 (dby < 0 && dby > -snap_distance) )
2831 dy = dbby - snap_h;
2832 }
2833
2834 if (screen->opaqueMove()) {
2835 configure(dx, dy, frame.width, frame.height);
2836 } else {
2837 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2838 frame.move_x, frame.move_y, frame.resize_w - 1,
2839 frame.resize_h - 1);
2840
2841 frame.move_x = dx;
2842 frame.move_y = dy;
2843
2844 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2845 frame.move_x, frame.move_y, frame.resize_w - 1,
2846 frame.resize_h - 1);
2847 }
2848
2849 screen->showPosition(dx, dy);
2850 }
2851
2852
2853 void OpenboxWindow::endMove() {
2854 ASSERT(flags.moving);
2855
2856 flags.moving = False;
2857
2858 openbox.maskWindowEvents(0, (OpenboxWindow *) 0);
2859 if (!screen->opaqueMove()) {
2860 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2861 frame.move_x, frame.move_y, frame.resize_w - 1,
2862 frame.resize_h - 1);
2863
2864 configure(frame.move_x, frame.move_y, frame.width, frame.height);
2865 openbox.ungrab();
2866 } else {
2867 configure(frame.x, frame.y, frame.width, frame.height);
2868 }
2869 screen->hideGeometry();
2870 XUngrabPointer(display, CurrentTime);
2871 // if there are any left over motions from the move, drop them now cuz they
2872 // cause problems
2873 XEvent e;
2874 while (XCheckTypedWindowEvent(display, frame.window, MotionNotify, &e));
2875 }
2876
2877
2878 void OpenboxWindow::motionNotifyEvent(XMotionEvent *me) {
2879 if (flags.moving)
2880 doMove(me->x_root, me->y_root);
2881 else if (!flags.resizing && (me->state & Button1Mask) && functions.move &&
2882 (frame.title == me->window || frame.label == me->window ||
2883 frame.handle == me->window || frame.window == me->window))
2884 startMove(me->x_root, me->y_root);
2885 else if (functions.resize &&
2886 (((me->state & Button1Mask) && (me->window == frame.right_grip ||
2887 me->window == frame.left_grip)) ||
2888 (me->state == (Mod1Mask | Button3Mask) &&
2889 me->window == frame.window))) {
2890 Bool left = resize_zone & ZoneLeft;
2891
2892 if (! flags.resizing) {
2893 Cursor cursor;
2894 if (resize_zone & ZoneTop)
2895 cursor = (resize_zone & ZoneLeft) ?
2896 openbox.getUpperLeftAngleCursor() :
2897 openbox.getUpperRightAngleCursor();
2898 else
2899 cursor = (resize_zone & ZoneLeft) ?
2900 openbox.getLowerLeftAngleCursor() :
2901 openbox.getLowerRightAngleCursor();
2902 XGrabPointer(display, me->window, False, ButtonMotionMask |
2903 ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None,
2904 cursor, CurrentTime);
2905
2906 flags.resizing = True;
2907
2908 openbox.grab();
2909
2910 int gx, gy;
2911 if (resize_zone & ZoneRight)
2912 frame.grab_x = me->x - screen->getBorderWidth();
2913 else
2914 frame.grab_x = me->x + screen->getBorderWidth();
2915 if (resize_zone & ZoneTop)
2916 frame.grab_y = me->y + screen->getBorderWidth() * 2;
2917 else
2918 frame.grab_y = me->y - screen->getBorderWidth() * 2;
2919 frame.resize_x = frame.x;
2920 frame.resize_y = frame.y;
2921 frame.resize_w = frame.width + (frame.border_w * 2);
2922 frame.resize_h = frame.height + (frame.border_w * 2);
2923
2924 if (left)
2925 left_fixsize(&gx, &gy);
2926 else
2927 right_fixsize(&gx, &gy);
2928
2929 screen->showGeometry(gx, gy);
2930
2931 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2932 frame.resize_x, frame.resize_y,
2933 frame.resize_w - 1, frame.resize_h - 1);
2934 } else {
2935 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2936 frame.resize_x, frame.resize_y,
2937 frame.resize_w - 1, frame.resize_h - 1);
2938
2939 int gx, gy;
2940
2941 if (resize_zone & ZoneTop)
2942 frame.resize_h = frame.height - (me->y - frame.grab_y);
2943 else
2944 frame.resize_h = frame.height + (me->y - frame.grab_y);
2945 if (frame.resize_h < 1) frame.resize_h = 1;
2946
2947 if (left) {
2948 frame.resize_x = me->x_root - frame.grab_x;
2949 if (frame.resize_x > (signed) (frame.x + frame.width))
2950 frame.resize_x = frame.resize_x + frame.width - 1;
2951
2952 left_fixsize(&gx, &gy);
2953 } else {
2954 frame.resize_w = frame.width + (me->x - frame.grab_x);
2955 if (frame.resize_w < 1) frame.resize_w = 1;
2956
2957 right_fixsize(&gx, &gy);
2958 }
2959
2960 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2961 frame.resize_x, frame.resize_y,
2962 frame.resize_w - 1, frame.resize_h - 1);
2963
2964 screen->showGeometry(gx, gy);
2965 }
2966 }
2967 }
2968
2969
2970 #ifdef SHAPE
2971 void OpenboxWindow::shapeEvent(XShapeEvent *) {
2972 if (openbox.hasShapeExtensions()) {
2973 if (flags.shaped) {
2974 openbox.grab();
2975 if (! validateClient()) return;
2976 XShapeCombineShape(display, frame.window, ShapeBounding,
2977 frame.mwm_border_w, frame.y_border +
2978 frame.mwm_border_w, client.window,
2979 ShapeBounding, ShapeSet);
2980
2981 int num = 1;
2982 XRectangle xrect[2];
2983 xrect[0].x = xrect[0].y = 0;
2984 xrect[0].width = frame.width;
2985 xrect[0].height = frame.y_border;
2986
2987 if (decorations.handle) {
2988 xrect[1].x = 0;
2989 xrect[1].y = frame.y_handle;
2990 xrect[1].width = frame.width;
2991 xrect[1].height = frame.handle_h + frame.border_w;
2992 num++;
2993 }
2994
2995 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
2996 xrect, num, ShapeUnion, Unsorted);
2997 openbox.ungrab();
2998 }
2999 }
3000 }
3001 #endif // SHAPE
3002
3003
3004 bool OpenboxWindow::validateClient(void) {
3005 XSync(display, False);
3006
3007 XEvent e;
3008 if (XCheckTypedWindowEvent(display, client.window, DestroyNotify, &e) ||
3009 XCheckTypedWindowEvent(display, client.window, UnmapNotify, &e)) {
3010 XPutBackEvent(display, &e);
3011 openbox.ungrab();
3012
3013 return false;
3014 }
3015
3016 return true;
3017 }
3018
3019
3020 void OpenboxWindow::restore(void) {
3021 XChangeSaveSet(display, client.window, SetModeDelete);
3022 XSelectInput(display, client.window, NoEventMask);
3023
3024 restoreGravity();
3025
3026 XUnmapWindow(display, frame.window);
3027 XUnmapWindow(display, client.window);
3028
3029 XSetWindowBorderWidth(display, client.window, client.old_bw);
3030 XReparentWindow(display, client.window, screen->getRootWindow(),
3031 client.x, client.y);
3032 XMapWindow(display, client.window);
3033
3034 XFlush(display);
3035
3036 delete this;
3037 }
3038
3039
3040 void OpenboxWindow::timeout(void) {
3041 screen->getWorkspace(workspace_number)->raiseWindow(this);
3042 }
3043
3044
3045 void OpenboxWindow::changeOpenboxHints(OpenboxHints *net) {
3046 if ((net->flags & AttribShaded) &&
3047 ((openbox_attrib.attrib & AttribShaded) !=
3048 (net->attrib & AttribShaded)))
3049 shade();
3050
3051 if (flags.visible && // watch out for requests when we can not be seen
3052 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3053 ((openbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3054 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3055 if (flags.maximized) {
3056 maximize(0);
3057 } else {
3058 int button = 0;
3059
3060 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3061 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3062 else if (net->flags & AttribMaxVert)
3063 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3064 else if (net->flags & AttribMaxHoriz)
3065 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3066
3067 maximize(button);
3068 }
3069 }
3070
3071 if ((net->flags & AttribOmnipresent) &&
3072 ((openbox_attrib.attrib & AttribOmnipresent) !=
3073 (net->attrib & AttribOmnipresent)))
3074 stick();
3075
3076 if ((net->flags & AttribWorkspace) &&
3077 (workspace_number != (signed) net->workspace)) {
3078 screen->reassociateWindow(this, net->workspace, True);
3079
3080 if (screen->getCurrentWorkspaceID() != (signed) net->workspace) withdraw();
3081 else deiconify();
3082 }
3083
3084 if (net->flags & AttribDecoration) {
3085 switch (net->decoration) {
3086 case DecorNone:
3087 decorations.titlebar = decorations.border = decorations.handle =
3088 decorations.iconify = decorations.maximize = decorations.menu = False;
3089
3090 break;
3091
3092 default:
3093 case DecorNormal:
3094 decorations.titlebar = decorations.iconify = decorations.menu =
3095 decorations.border = True;
3096 decorations.handle = (functions.resize && !flags.transient);
3097 decorations.maximize = functions.maximize;
3098
3099 break;
3100
3101 case DecorTiny:
3102 decorations.titlebar = decorations.iconify = decorations.menu = True;
3103 decorations.border = decorations.border = decorations.handle = False;
3104 decorations.maximize = functions.maximize;
3105
3106 break;
3107
3108 case DecorTool:
3109 decorations.titlebar = decorations.menu = True;
3110 decorations.iconify = decorations.border = False;
3111 decorations.handle = (functions.resize && !flags.transient);
3112 decorations.maximize = functions.maximize;
3113
3114 break;
3115 }
3116 if (frame.window) {
3117 XMapSubwindows(display, frame.window);
3118 XMapWindow(display, frame.window);
3119 }
3120
3121 reconfigure();
3122 setState(current_state);
3123 }
3124 }
3125
3126
3127 /*
3128 * Set the sizes of all components of the window frame
3129 * (the window decorations).
3130 * These values are based upon the current style settings and the client
3131 * window's dimentions.
3132 */
3133 void OpenboxWindow::upsize(void) {
3134 frame.bevel_w = screen->getBevelWidth();
3135
3136 if (decorations.border) {
3137 frame.border_w = screen->getBorderWidth();
3138 if (!flags.transient)
3139 frame.mwm_border_w = screen->getFrameWidth();
3140 else
3141 frame.mwm_border_w = 0;
3142 } else {
3143 frame.mwm_border_w = frame.border_w = 0;
3144 }
3145
3146 if (decorations.titlebar) {
3147 // the height of the titlebar is based upon the height of the font being
3148 // used to display the window's title
3149 WindowStyle *style = screen->getWindowStyle();
3150 if (i18n->multibyte())
3151 frame.title_h = (style->fontset_extents->max_ink_extent.height +
3152 (frame.bevel_w * 2) + 2);
3153 else
3154 frame.title_h = (style->font->ascent + style->font->descent +
3155 (frame.bevel_w * 2) + 2);
3156
3157 frame.label_h = frame.title_h - (frame.bevel_w * 2);
3158 frame.button_w = frame.button_h = (frame.label_h - 2);
3159 frame.y_border = frame.title_h + frame.border_w;
3160 } else {
3161 frame.title_h = 0;
3162 frame.label_h = 0;
3163 frame.button_w = frame.button_h = 0;
3164 frame.y_border = 0;
3165 }
3166
3167 frame.border_h = client.height + frame.mwm_border_w * 2;
3168
3169 if (decorations.handle) {
3170 frame.y_handle = frame.y_border + frame.border_h + frame.border_w;
3171 frame.grip_w = frame.button_w * 2;
3172 frame.grip_h = frame.handle_h = screen->getHandleWidth();
3173 } else {
3174 frame.y_handle = frame.y_border + frame.border_h;
3175 frame.handle_h = 0;
3176 frame.grip_w = frame.grip_h = 0;
3177 }
3178
3179 frame.width = client.width + (frame.mwm_border_w * 2);
3180 frame.height = frame.y_handle + frame.handle_h;
3181 }
3182
3183
3184 /*
3185 * Set the size and position of the client window.
3186 * These values are based upon the current style settings and the frame
3187 * window's dimensions.
3188 */
3189 void OpenboxWindow::downsize(void) {
3190 frame.y_handle = frame.height - frame.handle_h;
3191 frame.border_h = frame.y_handle - frame.y_border -
3192 (decorations.handle ? frame.border_w : 0);
3193
3194 client.x = frame.x + frame.mwm_border_w + frame.border_w;
3195 client.y = frame.y + frame.y_border + frame.mwm_border_w + frame.border_w;
3196
3197 client.width = frame.width - (frame.mwm_border_w * 2);
3198 client.height = frame.height - frame.y_border - (frame.mwm_border_w * 2)
3199 - frame.handle_h - (decorations.handle ? frame.border_w : 0);
3200
3201 frame.y_handle = frame.border_h + frame.y_border + frame.border_w;
3202 }
3203
3204
3205 void OpenboxWindow::right_fixsize(int *gx, int *gy) {
3206 // calculate the size of the client window and conform it to the
3207 // size specified by the size hints of the client window...
3208 int dx = frame.resize_w - client.base_width - (frame.mwm_border_w * 2) -
3209 (frame.border_w * 2) + (client.width_inc / 2);
3210 int dy = frame.resize_h - frame.y_border - client.base_height -
3211 frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2)
3212 + (client.height_inc / 2);
3213
3214 if (dx < (signed) client.min_width) dx = client.min_width;
3215 if (dy < (signed) client.min_height) dy = client.min_height;
3216 if ((unsigned) dx > client.max_width) dx = client.max_width;
3217 if ((unsigned) dy > client.max_height) dy = client.max_height;
3218
3219 dx /= client.width_inc;
3220 dy /= client.height_inc;
3221
3222 if (gx) *gx = dx;
3223 if (gy) *gy = dy;
3224
3225 dx = (dx * client.width_inc) + client.base_width;
3226 dy = (dy * client.height_inc) + client.base_height;
3227
3228 frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2);
3229 frame.resize_h = dy + frame.y_border + frame.handle_h +
3230 (frame.mwm_border_w * 2) + (frame.border_w * 3);
3231 if (resize_zone & ZoneTop)
3232 frame.resize_y = frame.y + frame.height - frame.resize_h +
3233 screen->getBorderWidth() * 2;
3234 }
3235
3236
3237 void OpenboxWindow::left_fixsize(int *gx, int *gy) {
3238 // calculate the size of the client window and conform it to the
3239 // size specified by the size hints of the client window...
3240 int dx = frame.x + frame.width - frame.resize_x - client.base_width -
3241 (frame.mwm_border_w * 2) + (client.width_inc / 2);
3242 int dy = frame.resize_h - frame.y_border - client.base_height -
3243 frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2)
3244 + (client.height_inc / 2);
3245
3246 if (dx < (signed) client.min_width) dx = client.min_width;
3247 if (dy < (signed) client.min_height) dy = client.min_height;
3248 if ((unsigned) dx > client.max_width) dx = client.max_width;
3249 if ((unsigned) dy > client.max_height) dy = client.max_height;
3250
3251 dx /= client.width_inc;
3252 dy /= client.height_inc;
3253
3254 if (gx) *gx = dx;
3255 if (gy) *gy = dy;
3256
3257 dx = (dx * client.width_inc) + client.base_width;
3258 dy = (dy * client.height_inc) + client.base_height;
3259
3260 frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2);
3261 frame.resize_x = frame.x + frame.width - frame.resize_w +
3262 (frame.border_w * 2);
3263 frame.resize_h = dy + frame.y_border + frame.handle_h +
3264 (frame.mwm_border_w * 2) + (frame.border_w * 3);
3265 if (resize_zone & ZoneTop)
3266 frame.resize_y = frame.y + frame.height - frame.resize_h +
3267 screen->getBorderWidth() * 2;
3268
3269 }
This page took 0.197642 seconds and 4 git commands to generate.