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