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