X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2FWindow.cc;h=a90e5183e36a4b56ce8654dfe27373d7c7a7a8a2;hb=23640740ca6659ee4effb9e5c040900e0bbdeb59;hp=7ca881ac4a7e938fba2d57fcdf98e7b73c1c0006;hpb=8794d357e67abddf9fda9db77b235e294d0ec590;p=chaz%2Fopenbox diff --git a/src/Window.cc b/src/Window.cc index 7ca881ac..a90e5183 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -55,6 +55,7 @@ extern "C" { #include "Workspace.hh" #include "Slit.hh" +using std::string; /* * Initializes the class with default values/the window's set initial values. @@ -649,54 +650,86 @@ void BlackboxWindow::destroyMaximizeButton(void) { void BlackboxWindow::positionButtons(bool redecorate_label) { - unsigned int bw = frame.button_w + frame.bevel_w + 1, - by = frame.bevel_w + 1, lx = by, lw = frame.inside_w - by; - - if (decorations & Decor_Iconify) { - if (frame.iconify_button == None) createIconifyButton(); - - XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, by, by, - frame.button_w, frame.button_w); - XMapWindow(blackbox->getXDisplay(), frame.iconify_button); - XClearWindow(blackbox->getXDisplay(), frame.iconify_button); - - lx += bw; - lw -= bw; - } else if (frame.iconify_button) { - destroyIconifyButton(); + string layout = blackbox->getTitlebarLayout(); + string parsed; + + bool hasclose, hasiconify, hasmaximize, haslabel; + hasclose = hasiconify = hasmaximize = haslabel = false; + + string::const_iterator it, end; + for (it = layout.begin(), end = layout.end(); it != end; ++it) { + switch(*it) { + case 'C': + if (! hasclose && (decorations & Decor_Close)) { + hasclose = true; + parsed += *it; + } + break; + case 'I': + if (! hasiconify && (decorations & Decor_Iconify)) { + hasiconify = true; + parsed += *it; + } + break; + case 'M': + if (! hasmaximize && (decorations & Decor_Maximize)) { + hasmaximize = true; + parsed += *it; + } + break; + case 'L': + if (! haslabel) { + haslabel = true; + parsed += *it; + } + } } - int bx = frame.inside_w - bw; - - if (decorations & Decor_Close) { - if (frame.close_button == None) createCloseButton(); - - XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, bx, by, - frame.button_w, frame.button_w); - XMapWindow(blackbox->getXDisplay(), frame.close_button); - XClearWindow(blackbox->getXDisplay(), frame.close_button); - - bx -= bw; - lw -= bw; - } else if (frame.close_button) { + if (! hasclose && frame.close_button) destroyCloseButton(); - } - if (decorations & Decor_Maximize) { - if (frame.maximize_button == None) createMaximizeButton(); - - XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, bx, by, - frame.button_w, frame.button_w); - XMapWindow(blackbox->getXDisplay(), frame.maximize_button); - XClearWindow(blackbox->getXDisplay(), frame.maximize_button); - - lw -= bw; - } else if (frame.maximize_button) { + if (! hasiconify && frame.iconify_button) + destroyIconifyButton(); + if (! hasmaximize && frame.maximize_button) destroyMaximizeButton(); + if (! haslabel) + parsed += 'L'; // require that the label be in the layout + + const unsigned int bsep = frame.bevel_w + 1; // separation between elements + const unsigned int by = frame.bevel_w + 1; + const unsigned int ty = frame.bevel_w; + + frame.label_w = frame.inside_w - bsep * 2 - + (frame.button_w + bsep) * (parsed.size() - 1); + + unsigned int x = bsep; + for (it = parsed.begin(), end = parsed.end(); it != end; ++it) { + switch(*it) { + case 'C': + if (!frame.close_button) createCloseButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'I': + if (!frame.iconify_button) createIconifyButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'M': + if (!frame.maximize_button) createMaximizeButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'L': + XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty, + frame.label_w, frame.label_h); + x += frame.label_w + bsep; + break; + } } - frame.label_w = lw - by; - XMoveResizeWindow(blackbox->getXDisplay(), frame.label, lx, frame.bevel_w, - frame.label_w, frame.label_h); - if (redecorate_label) decorateLabel(); + if (redecorate_label) decorateLabel(); redrawLabel(); redrawAllButtons(); } @@ -772,9 +805,10 @@ void BlackboxWindow::positionWindows(void) { XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip, frame.border_w); + // use client.rect here so the value is correct even if shaded XMoveResizeWindow(blackbox->getXDisplay(), frame.handle, -frame.border_w, - frame.rect.height() - frame.margin.bottom + + client.rect.height() + frame.margin.top + frame.mwm_border_w - frame.border_w, frame.inside_w, frame.handle_h); XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip, @@ -783,6 +817,7 @@ void BlackboxWindow::positionWindows(void) { XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip, frame.inside_w - frame.grip_w - frame.border_w, -frame.border_w, frame.grip_w, frame.handle_h); + XMapSubwindows(blackbox->getXDisplay(), frame.handle); XMapWindow(blackbox->getXDisplay(), frame.handle); } else if (frame.handle) { @@ -906,12 +941,18 @@ void BlackboxWindow::getWMNormalHints(void) { long icccm_mask; XSizeHints sizehint; - const Rect& screen_area = screen->availableArea(); - client.min_width = client.min_height = client.width_inc = client.height_inc = 1; client.base_width = client.base_height = 0; + + /* + use the full screen, not the strut modified size. otherwise when the + availableArea changes max_width/height will be incorrect and lead to odd + rendering bugs. + */ + const Rect& screen_area = screen->getRect(); client.max_width = screen_area.width(); + client.max_height = screen_area.height(); client.min_aspect_x = client.min_aspect_y = client.max_aspect_x = client.max_aspect_y = 1; @@ -1119,8 +1160,8 @@ void BlackboxWindow::getTransientInfo(void) { client.transient_for = 0; Window trans_for; - if (!XGetTransientForHint(blackbox->getXDisplay(), client.window, - &trans_for)) { + if (! XGetTransientForHint(blackbox->getXDisplay(), client.window, + &trans_for)) { // transient_for hint not set return; } @@ -1442,10 +1483,12 @@ void BlackboxWindow::maximize(unsigned int button) { blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert); blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert); - // when a resize is begun, maximize(0) is called to clear any maximization - // flags currently set. Otherwise it still thinks it is maximized. - // so we do not need to call configure() because resizing will handle it - if (!flags.resizing) + /* + when a resize is begun, maximize(0) is called to clear any maximization + flags currently set. Otherwise it still thinks it is maximized. + so we do not need to call configure() because resizing will handle it + */ + if (! flags.resizing) configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y, blackbox_attrib.premax_w, blackbox_attrib.premax_h); @@ -1460,7 +1503,9 @@ void BlackboxWindow::maximize(unsigned int button) { blackbox_attrib.premax_x = frame.rect.x(); blackbox_attrib.premax_y = frame.rect.y(); blackbox_attrib.premax_w = frame.rect.width(); - blackbox_attrib.premax_h = frame.rect.height(); + // use client.rect so that clients can be restored even if shaded + blackbox_attrib.premax_h = + client.rect.height() + frame.margin.top + frame.margin.bottom; const Rect &screen_area = screen->availableArea(); frame.changing = screen_area; @@ -1499,7 +1544,8 @@ void BlackboxWindow::maximize(unsigned int button) { configure(frame.changing.x(), frame.changing.y(), frame.changing.width(), frame.changing.height()); - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + if (flags.focused) + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); redrawAllButtons(); setState(current_state); } @@ -1532,9 +1578,6 @@ void BlackboxWindow::setWorkspace(unsigned int n) { void BlackboxWindow::shade(void) { - if (! (decorations & Decor_Titlebar)) - return; - if (flags.shaded) { XResizeWindow(blackbox->getXDisplay(), frame.window, frame.inside_w, frame.inside_h); @@ -1548,6 +1591,9 @@ void BlackboxWindow::shade(void) { frame.rect.setHeight(client.rect.height() + frame.margin.top + frame.margin.bottom); } else { + if (! (decorations & Decor_Titlebar)) + return; + XResizeWindow(blackbox->getXDisplay(), frame.window, frame.inside_w, frame.title_h); flags.shaded = True; @@ -1767,7 +1813,7 @@ void BlackboxWindow::restoreAttributes(void) { blackbox->getBlackboxAttributesAtom(), &atom_return, &foo, &nitems, &ulfoo, (unsigned char **) &net); - if (ret != Success || !net || nitems != PropBlackboxAttributesElements) + if (ret != Success || ! net || nitems != PropBlackboxAttributesElements) return; if (net->flags & AttribShaded && @@ -1835,11 +1881,13 @@ void BlackboxWindow::setGravityOffsets(void) { // x coordinates for each gravity type const int x_west = client.rect.x(); const int x_east = client.rect.right() - frame.inside_w + 1; - const int x_center = client.rect.right() - (frame.rect.width()/2) + 1; + const int x_center = client.rect.left() + + ((client.rect.width() - frame.rect.width()) / 2); // y coordinates for each gravity type const int y_north = client.rect.y(); const int y_south = client.rect.bottom() - frame.inside_h + 1; - const int y_center = client.rect.bottom() - (frame.rect.height()/2) + 1; + const int y_center = client.rect.top() + + ((client.rect.height() - frame.rect.height()) / 2); switch (client.win_gravity) { default: @@ -1870,13 +1918,13 @@ void BlackboxWindow::restoreGravity(void) { // x coordinates for each gravity type const int x_west = frame.rect.x(); const int x_east = frame.rect.x() + frame.inside_w - client.rect.width(); - const int x_center = frame.rect.x() + (frame.rect.width()/2) - - client.rect.width(); + const int x_center = frame.rect.x() - + ((client.rect.width() - frame.rect.width()) / 2); // y coordinates for each gravity type const int y_north = frame.rect.y(); const int y_south = frame.rect.y() + frame.inside_h - client.rect.height(); - const int y_center = frame.rect.y() + (frame.rect.height()/2) - - client.rect.height(); + const int y_center = frame.rect.y() - + ((client.rect.height() - frame.rect.height()) / 2); switch(client.win_gravity) { default: @@ -2335,7 +2383,7 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) { // snap the window menu into a corner if necessary - we check the // position of the menu with the coordinates of the client to // make the comparisions easier. - // ### this needs some work! + // XXX: this needs some work! if (mx > client.rect.right() - static_cast(windowmenu->getWidth())) mx = frame.rect.right() - windowmenu->getWidth() - frame.border_w + 1; @@ -2360,6 +2408,18 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) { windowmenu->hide(); } } + // mouse wheel up + } else if (be->button == 4) { + if ((be->window == frame.label || + be->window == frame.title) && + ! flags.shaded) + shade(); + // mouse wheel down + } else if (be->button == 5) { + if ((be->window == frame.label || + be->window == frame.title) && + flags.shaded) + shade(); } } @@ -2432,7 +2492,7 @@ void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) { void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) { - if (!flags.resizing && (me->state & Button1Mask) && + if (! flags.resizing && (me->state & Button1Mask) && (functions & Func_Move) && (frame.title == me->window || frame.label == me->window || frame.handle == me->window || frame.window == me->window)) { @@ -2468,30 +2528,72 @@ void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) { const int snap_distance = screen->getEdgeSnapThreshold(); if (snap_distance) { - Rect srect = screen->availableArea(); // window corners const int wleft = dx, wright = dx + frame.rect.width() - 1, wtop = dy, wbottom = dy + frame.rect.height() - 1; + // Maybe this should be saved in the class, and set in the setWorkspace + // function!! + Workspace *w = screen->getWorkspace(getWorkspaceNumber()); + assert(w); + + // try snap to another window + for (unsigned int i = 0, c = w->getCount(); i < c; ++i) { + BlackboxWindow *snapwin = w->getWindow(i); + if (snapwin == this) + continue; // don't snap to self + + const Rect &winrect = snapwin->frameRect(); + int dleft = std::abs(wright - winrect.left()), + dright = std::abs(wleft - winrect.right()), + dtop = std::abs(wbottom - winrect.top()), + dbottom = std::abs(wtop - winrect.bottom()); + + // snap left? + if (dleft < snap_distance && dleft <= dright) { + dx = winrect.left() - frame.rect.width(); + continue; + } + // snap right? + else if (dright < snap_distance) { + dx = winrect.right() + 1; + continue; + } + + // snap top? + if (dtop < snap_distance && dtop <= dbottom) { + dy = winrect.top() - frame.rect.height(); + continue; + } + // snap bottom? + else if (dbottom < snap_distance) { + dy = winrect.bottom() + 1; + continue; + } + } + + // try snap to the screen's available area + Rect srect = screen->availableArea(); + int dleft = std::abs(wleft - srect.left()), dright = std::abs(wright - srect.right()), dtop = std::abs(wtop - srect.top()), dbottom = std::abs(wbottom - srect.bottom()); // snap left? - if (dleft < snap_distance && dleft < dright) + if (dleft < snap_distance && dleft <= dright) dx = srect.left(); // snap right? - else if (dright < snap_distance && dright < dleft) + else if (dright < snap_distance) dx = srect.right() - frame.rect.width() + 1; // snap top? - if (dtop < snap_distance && dtop < dbottom) + if (dtop < snap_distance && dtop <= dbottom) dy = srect.top(); // snap bottom? - else if (dbottom < snap_distance && dbottom < dtop) + else if (dbottom < snap_distance) dy = srect.bottom() - frame.rect.height() + 1; srect = screen->getRect(); // now get the full screen @@ -2502,17 +2604,17 @@ void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) { dbottom = std::abs(wbottom - srect.bottom()); // snap left? - if (dleft < snap_distance && dleft < dright) + if (dleft < snap_distance && dleft <= dright) dx = srect.left(); // snap right? - else if (dright < snap_distance && dright < dleft) + else if (dright < snap_distance) dx = srect.right() - frame.rect.width() + 1; // snap top? - if (dtop < snap_distance && dtop < dbottom) + if (dtop < snap_distance && dtop <= dbottom) dy = srect.top(); // snap bottom? - else if (dbottom < snap_distance && dbottom < dtop) + else if (dbottom < snap_distance) dy = srect.bottom() - frame.rect.height() + 1; } @@ -2640,8 +2742,10 @@ void BlackboxWindow::restore(bool remap) { XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw); XEvent ev; - if (! XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, - ReparentNotify, &ev)) { + if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, + ReparentNotify, &ev)) { + remap = True; + } else { // according to the ICCCM - if the client doesn't reparent to // root, then we have to do it for them XReparentWindow(blackbox->getXDisplay(), client.window, @@ -2730,6 +2834,11 @@ void BlackboxWindow::changeBlackboxHints(BlackboxHints *net) { break; } + + // we can not be shaded if we lack a titlebar + if (flags.shaded && ! (decorations & Decor_Titlebar)) + shade(); + if (frame.window) { XMapSubwindows(blackbox->getXDisplay(), frame.window); XMapWindow(blackbox->getXDisplay(), frame.window); @@ -2752,7 +2861,7 @@ void BlackboxWindow::upsize(void) { if (decorations & Decor_Border) { frame.border_w = screen->getBorderWidth(); - if (!isTransient()) + if (! isTransient()) frame.mwm_border_w = screen->getFrameWidth(); else frame.mwm_border_w = 0; @@ -2804,13 +2913,23 @@ void BlackboxWindow::upsize(void) { frame.margin.bottom = frame.border_w + frame.mwm_border_w; } - // set the frame rect - frame.rect.setSize(client.rect.width() + frame.margin.left + - frame.margin.right, - client.rect.height() + frame.margin.top + - frame.margin.bottom); - frame.inside_w = frame.rect.width() - (frame.border_w * 2); - frame.inside_h = frame.rect.height() - (frame.border_w * 2); + /* + We first get the normal dimensions and use this to define the inside_w/h + then we modify the height if shading is in effect. + If the shade state is not considered then frame.rect gets reset to the + normal window size on a reconfigure() call resulting in improper + dimensions appearing in move/resize and other events. + */ + unsigned int + height = client.rect.height() + frame.margin.top + frame.margin.bottom, + width = client.rect.width() + frame.margin.left + frame.margin.right; + + frame.inside_w = width - (frame.border_w * 2); + frame.inside_h = height - (frame.border_w * 2); + + if (flags.shaded) + height = frame.title_h + (frame.border_w * 2); + frame.rect.setSize(width, height); } @@ -2820,8 +2939,7 @@ void BlackboxWindow::upsize(void) { * * The logical width and height are placed into pw and ph, if they * are non-zero. Logical size refers to the users perception of - * the window size (for example an xterm has resizes in cells, not in - * pixels). + * the window size (for example an xterm resizes in cells, not in pixels). * * The physical geometry is placed into frame.changing_{x,y,width,height}. * Physical geometry refers to the geometry of the window in pixels. @@ -2917,8 +3035,24 @@ int WindowStyle::doJustify(const char *text, int &start_pos, BWindowGroup::BWindowGroup(Blackbox *b, Window _group) : blackbox(b), group(_group) { - // watch for destroy notify on the group window - XSelectInput(blackbox->getXDisplay(), group, StructureNotifyMask); + XWindowAttributes wattrib; + if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) { + // group window doesn't seem to exist anymore + delete this; + return; + } + + /* + watch for destroy notify on the group window (in addition to + any other events we are looking for) + + since some managed windows can also be window group controllers, + we need to make sure that we don't clobber the event mask for the + managed window + */ + XSelectInput(blackbox->getXDisplay(), group, + wattrib.your_event_mask | StructureNotifyMask); + blackbox->saveGroupSearch(group, this); }