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