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