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