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