Skip to content
Snippets Groups Projects
client.c 148 KiB
Newer Older
Olivier Fourdan's avatar
Id  
Olivier Fourdan committed
/*      $Id$
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2, or (at your option)
        any later version.
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Olivier Fourdan's avatar
Olivier Fourdan committed
        oroborus - (c) 2001 Ken Lynch
        xfwm4    - (c) 2002-2006 Olivier Fourdan
Olivier Fourdan's avatar
Olivier Fourdan committed
 */
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_CONFIG_H
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "config.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#endif

#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <libxfce4util/libxfce4util.h>
Olivier Fourdan's avatar
Olivier Fourdan committed

#include "client.h"
#include "compositor.h"
#include "focus.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "frame.h"
#include "hints.h"
#include "mypixmap.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "mywindow.h"
#include "session.h"
#include "startup_notification.h"
#include "tabwin.h"
#include "transients.h"
#include "wireframe.h"
#include "workspaces.h"
Olivier Fourdan's avatar
Olivier Fourdan committed

#define POINTER_EVENT_MASK \
    ButtonPressMask|\
#define FRAME_EVENT_MASK \
    SubstructureNotifyMask|\
Olivier Fourdan's avatar
Olivier Fourdan committed
    EnterWindowMask|\
    PropertyChangeMask
#define CLIENT_EVENT_MASK \
#define BUTTON_EVENT_MASK \
    EnterWindowMask|\
    LeaveWindowMask

Olivier Fourdan's avatar
Olivier Fourdan committed
#define START_ICONIC(c) \
    ((c->wmhints) && \
     (c->wmhints->initial_state == IconicState) && \
Olivier Fourdan's avatar
Olivier Fourdan committed

#define OPACITY_SET_STEP        (guint) 0x16000000
#define OPACITY_SET_MIN         (guint) 0x40000000

typedef struct _MoveResizeData MoveResizeData;
struct _MoveResizeData
{
    int cancel_x, cancel_y; /* for cancellation (either position or size) */
};

typedef struct _ClientCycleData ClientCycleData;
struct _ClientCycleData
{
    Client *c;
    Tabwin *tabwin;
    int cycle_range;
};

typedef struct _ButtonPressData ButtonPressData;
struct _ButtonPressData
{
    int b;
    Client *c;
};

Olivier Fourdan's avatar
Olivier Fourdan committed
static void
Display *
clientGetXDisplay (Client * c)
{
    g_return_val_if_fail (c, NULL);

    return myScreenGetXDisplay (c->screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed

void
clientInstallColormaps (Client * c)
{
    XWindowAttributes attr;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean installed;
    g_return_if_fail (c != NULL);
    TRACE ("entering clientInstallColormaps");
Olivier Fourdan's avatar
Olivier Fourdan committed
    installed = FALSE;
        for (i = c->ncmap - 1; i >= 0; i--)
        {
            XGetWindowAttributes (clientGetXDisplay (c), c->cmap_windows[i], &attr);
            XInstallColormap (clientGetXDisplay (c), attr.colormap);
            if (c->cmap_windows[i] == c->window)
            {
                installed = TRUE;
            }
        }
    if ((!installed) && (c->cmap))
        XInstallColormap (clientGetXDisplay (c), c->cmap);
void
clientUpdateColormaps (Client * c)
    g_return_if_fail (c != NULL);
    TRACE ("entering clientUpdateColormaps");
        XFree (c->cmap_windows);
Olivier Fourdan's avatar
Olivier Fourdan committed
        c->ncmap = 0;
    if (!XGetWMColormapWindows (clientGetXDisplay (c), c->window, &c->cmap_windows, &c->ncmap))
Olivier Fourdan's avatar
Olivier Fourdan committed
        c->cmap_windows = NULL;
void
clientUpdateName (Client * c)
{
    ScreenInfo *screen_info;
    DisplayInfo *display_info;
    gchar *name;

    g_return_if_fail (c != NULL);
    TRACE ("entering clientUpdateName");

    screen_info = c->screen_info;
    display_info = screen_info->display_info;

    getWindowName (display_info, c->window, &name);
    if (name)
    {
        if (c->name)
        {
            if (strcmp (name, c->name))
            {
                g_free (c->name);
                c->name = name;
                FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
                frameQueueDraw (c);
            }
        }
    }
}

clientUpdateAllFrames (ScreenInfo *screen_info, int mask)
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c;
Olivier Fourdan's avatar
Olivier Fourdan committed
    int i;
    g_return_if_fail (screen_info != NULL);
    TRACE ("entering clientRedrawAllFrames");
    myScreenGrabPointer (screen_info, EnterWindowMask, None, myDisplayGetCurrentTime (screen_info->display_info));
    for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, i++)
        if (mask & UPDATE_BUTTON_GRABS)
        {
            clientUngrabButtons (c);
            clientGrabButtons (c);
            clientGrabMouseButton (c);
        }
        if (mask & UPDATE_CACHE)
        {
        }
        if (mask & UPDATE_GRAVITY)
        {
            clientGravitate (c, REMOVE);
            clientGravitate (c, APPLY);
            setNetFrameExtents (screen_info->display_info,
                                c->window,
            configure_flags |= CFG_FORCE_REDRAW;
            mask &= ~UPDATE_FRAME;
        }
        if (mask & UPDATE_MAXIMIZE)
        {
            unsigned long maximization_flags = 0L;

            /* Recompute size and position of maximized windows */
            if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT))
            {
                 maximization_flags |= FLAG_TEST (c->flags,
                     CLIENT_FLAG_MAXIMIZED_HORIZ) ? WIN_STATE_MAXIMIZED_HORIZ : 0;
                 maximization_flags |= FLAG_TEST (c->flags,
                     CLIENT_FLAG_MAXIMIZED_VERT) ? WIN_STATE_MAXIMIZED_VERT : 0;

                 /* Force an update by clearing the internal flags */
                 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
                 clientToggleMaximized (c, maximization_flags, FALSE);

                 configure_flags |= CFG_FORCE_REDRAW;
                 mask &= ~UPDATE_FRAME;
            }
        }
        if (configure_flags != 0L)
        {
             wc.x = c->x;
             wc.y = c->y;
             wc.width = c->width;
             wc.height = c->height;
             clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, configure_flags);
    myScreenUngrabPointer (screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    g_return_if_fail (c != NULL);
    TRACE ("entering clientGrabButtons");
    TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
    screen_info = c->screen_info;
    if (screen_info->params->easy_click)
    {
        grabButton(clientGetXDisplay (c), AnyButton, screen_info->params->easy_click, c->window);
}

void
clientUngrabButtons (Client * c)
{
    g_return_if_fail (c != NULL);
    TRACE ("entering clientUngrabButtons");
    TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
    XUngrabButton (clientGetXDisplay (c), AnyButton, AnyModifier, c->window);
static gboolean
urgent_cb (gpointer data)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c;

    TRACE ("entering urgent_cb");

Olivier Fourdan's avatar
Olivier Fourdan committed
    c = (Client *) data;
    if (c != clientGetFocus ())
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
    }
    return (TRUE);
}

void
clientUpdateUrgency (Client *c)
{
    g_return_if_fail (c != NULL);
    TRACE ("entering clientUpdateUrgency");

Olivier Fourdan's avatar
Olivier Fourdan committed
    FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
    if (c->blink_timeout_id)
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        g_source_remove (c->blink_timeout_id);
Olivier Fourdan's avatar
Olivier Fourdan committed
    FLAG_UNSET (c->wm_flags, WM_FLAG_URGENT);

    c->blink_timeout_id = 0;
    if ((c->wmhints) && (c->wmhints->flags & XUrgencyHint))
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        FLAG_SET (c->wm_flags, WM_FLAG_URGENT);
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
        {
            c->blink_timeout_id =
Olivier Fourdan's avatar
Olivier Fourdan committed
                g_timeout_add_full (G_PRIORITY_DEFAULT,
                                    CLIENT_BLINK_TIMEOUT,
                                    (GtkFunction) urgent_cb,
                                    (gpointer) c, NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE)
        && !FLAG_TEST (c->wm_flags, WM_FLAG_URGENT)
        && (c != clientGetFocus ()))
Olivier Fourdan's avatar
Olivier Fourdan committed
        FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
void
clientCoordGravitate (Client * c, int mode, int *x, int *y)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    int dx, dy;
Olivier Fourdan's avatar
Olivier Fourdan committed

    g_return_if_fail (c != NULL);
    TRACE ("entering clientCoordGravitate");
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    c->gravity = c->size->flags & PWinGravity ? c->size->win_gravity : NorthWestGravity;
Olivier Fourdan's avatar
Olivier Fourdan committed
    switch (c->gravity)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
            dx = (c->border_width * 2) - ((frameLeft (c) +
                    frameRight (c)) / 2);
            dy = (c->border_width * 2) - ((frameTop (c) +
                    frameBottom (c)) / 2);
            dx = (c->border_width * 2) - ((frameLeft (c) +
                    frameRight (c)) / 2);
            dy = frameTop (c);
            break;
        case SouthGravity:
            dx = (c->border_width * 2) - ((frameLeft (c) +
                    frameRight (c)) / 2);
            dy = (c->border_width * 2) - frameBottom (c);
            dx = (c->border_width * 2) - frameRight (c);
            dy = (c->border_width * 2) - ((frameTop (c) +
                    frameBottom (c)) / 2);
            break;
        case WestGravity:
            dx = frameLeft (c);
            dy = (c->border_width * 2) - ((frameTop (c) +
                    frameBottom (c)) / 2);
            break;
        case NorthWestGravity:
            dx = frameLeft (c);
            dy = frameTop (c);
            break;
        case NorthEastGravity:
            dx = (c->border_width * 2) - frameRight (c);
            dy = frameTop (c);
            break;
        case SouthWestGravity:
            dx = frameLeft (c);
            dy = (c->border_width * 2) - frameBottom (c);
            break;
        case SouthEastGravity:
            dx = (c->border_width * 2) - frameRight (c);
            dy = (c->border_width * 2) - frameBottom (c);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    *x = *x + (dx * mode);
    *y = *y + (dy * mode);
}

void
clientGravitate (Client * c, int mode)
    g_return_if_fail (c != NULL);
    TRACE ("entering clientGravitate");

    x = c->x;
    y = c->y;
    clientCoordGravitate (c, mode, &x, &y);
    c->x = x;
    c->y = y;
clientComputeWidth (Client * c, int *w)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    int w2;

    g_return_if_fail (c != NULL);
    g_return_if_fail (w != NULL);
    TRACE ("entering clientComputeWidth");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Bypass resize increment and max sizes for fullscreen */
    if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
        && !(FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
             && (c->screen_info->params->borderless_maximize)))
        if ((c->size->flags & PResizeInc) && (c->size->width_inc))
            w2 = (*w - c->size->min_width) / c->size->width_inc;
            *w = c->size->min_width + (w2 * c->size->width_inc);
        }
        if (c->size->flags & PMaxSize)
        {
            if (*w > c->size->max_width)
            {
                *w = c->size->max_width;
            }
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    if (c->size->flags & PMinSize)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
clientSetWidth (Client * c, int w)
{
    int temp;

    g_return_if_fail (c != NULL);
    TRACE ("entering clientSetWidth");
    TRACE ("setting width %i for client \"%s\" (0x%lx)", w, c->name, c->window);

    temp = w;
    clientComputeWidth (c, &temp);
    c->width = temp;
}

static void
clientComputeHeight (Client * c, int *h)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    int h2;

    g_return_if_fail (c != NULL);
    TRACE ("entering clientComputeHeight");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Bypass resize increment and max sizes for fullscreen */
    if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
        && !(FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
             && (c->screen_info->params->borderless_maximize)))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        if ((c->size->flags & PResizeInc) && (c->size->height_inc))
            h2 = (*h - c->size->min_height) / c->size->height_inc;
            *h = c->size->min_height + (h2 * c->size->height_inc);
        }
        if (c->size->flags & PMaxSize)
        {
            if (*h > c->size->max_height)
            {
                *h = c->size->max_height;
            }
Olivier Fourdan's avatar
Olivier Fourdan committed
    }

static void
clientSetHeight (Client * c, int h)
{
    int temp;

    g_return_if_fail (c != NULL);
    TRACE ("entering clientSetHeight");
    TRACE ("setting height %i for client \"%s\" (0x%lx)", h, c->name, c->window);

    temp = h;
    clientComputeHeight (c, &temp);
    c->height = temp;
}

Olivier Fourdan's avatar
Olivier Fourdan committed
/* clientConstrainRatio - adjust the given width and height to account for
   the constraints imposed by size hints

   The aspect ratio stuff, is borrowed from uwm's CheckConsistency routine.
 */

#define MAKE_MULT(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
static void
clientConstrainRatio (Client * c, int *w, int *h, int corner)
{

    g_return_if_fail (c != NULL);
    TRACE ("entering clientConstrainRatio");
    TRACE ("client \"%s\" (0x%lx)", c->name, c->window);

    if (c->size->flags & PAspect)
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        int xinc, yinc, minx, miny, maxx, maxy, delta;

        xinc = c->size->width_inc;
        yinc = c->size->height_inc;
        minx = c->size->min_aspect.x;
        miny = c->size->min_aspect.y;
        maxx = c->size->max_aspect.x;
        maxy = c->size->max_aspect.y;
        if ((minx * *h > miny * *w) && (miny) &&
            ((corner == CORNER_COUNT + SIDE_TOP) || (corner == CORNER_COUNT + SIDE_BOTTOM)))
        {
            /* Change width to match */
            delta = MAKE_MULT (minx * *h /  miny - *w, xinc);
            if (!(c->size->flags & PMaxSize) ||
        if ((minx * *h > miny * *w) && (minx))
            delta = MAKE_MULT (*h - *w * miny / minx, yinc);
            if (!(c->size->flags & PMinSize) ||
                (*h - delta >= c->size->min_height))
                delta = MAKE_MULT (minx * *h / miny - *w, xinc);
                    (*w + delta <= c->size->max_width))
                  *w += delta;
        if ((maxx * *h < maxy * *w) && (maxx) &&
            ((corner == CORNER_COUNT + SIDE_LEFT) || (corner == CORNER_COUNT + SIDE_RIGHT)))
            delta = MAKE_MULT (*w * maxy / maxx - *h, yinc);
            if (!(c->size->flags & PMaxSize) ||
                (*h + delta <= c->size->max_height))
        if ((maxx * *h < maxy * *w) && (maxy))
            delta = MAKE_MULT (*w - maxx * *h / maxy, xinc);
            if (!(c->size->flags & PMinSize) ||
                delta = MAKE_MULT (*w * maxy / maxx - *h, yinc);
                    (*h + delta <= c->size->max_height))
Olivier Fourdan's avatar
Olivier Fourdan committed
#define WIN_MOVED   (mask & (CWX | CWY))
#define WIN_RESIZED (mask & (CWWidth | CWHeight))

Olivier Fourdan's avatar
Olivier Fourdan committed
static void
clientConfigureWindows (Client * c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
{
    unsigned long change_mask;
    XWindowChanges change_values;

    change_mask = (mask & (CWX | CWY | CWWidth | CWHeight));
    if (flags & CFG_FORCE_REDRAW)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
    }

    if (change_mask & (CWX | CWY | CWWidth | CWHeight))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        change_values.x = frameX (c);
        change_values.y = frameY (c);
        change_values.width = frameWidth (c);
        change_values.height = frameHeight (c);
        XConfigureWindow (clientGetXDisplay (c), c->frame, change_mask, &change_values);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (WIN_RESIZED || (flags & CFG_FORCE_REDRAW))
        {
            frameDraw (c, (flags & CFG_FORCE_REDRAW));
        }

        change_values.x = frameLeft (c);
        change_values.y = frameTop (c);
        change_values.width = c->width;
        change_values.height = c->height;
        XConfigureWindow (clientGetXDisplay (c), c->window, change_mask, &change_values);
clientConfigure (Client * c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    XConfigureEvent ce;
Olivier Fourdan's avatar
Olivier Fourdan committed
    int px, py, pwidth, pheight;
    g_return_if_fail (c != NULL);
    g_return_if_fail (c->window != None);
    TRACE ("entering clientConfigure");
    TRACE ("configuring client \"%s\" (0x%lx) %s, type %u", c->name,
        c->window, flags & CFG_CONSTRAINED ? "constrained" : "not contrained", c->type);
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
        if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
        clientSetWidth (c, wc->width);
        clientSetHeight (c, wc->height);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    if (mask & CWBorderWidth)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        c->border_width = wc->border_width;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
             * Limitation: we don't support neither
             * TopIf, BottomIf nor Opposite ...
            case Above:
                TRACE ("Above");
                if (mask & CWSibling)
                {
                    clientRaise (c, wc->sibling);
                }
                else
                {
                    clientRaise (c, None);
                }
                TRACE ("Below");
                if (mask & CWSibling)
                {
                    clientLower (c, wc->sibling);
                }
                else
            case TopIf:
            case BottomIf:
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Keep control over what the application does. However, some broken apps try
       to achieve fullscreen by using static gravity and a (0,0) position, the
       second part of the test is for this case.
    if (((flags & (CFG_CONSTRAINED | CFG_REQUEST)) == (CFG_CONSTRAINED | CFG_REQUEST))
         && !((c->gravity == StaticGravity) && (c->x == 0) && (c->y == 0)))
Olivier Fourdan's avatar
Olivier Fourdan committed
        px = c->x;
        py = c->y;
        pwidth = c->width;
        pheight = c->height;
        /* Keep fully visible only on resize */
        clientConstrainPos (c, (mask & (CWWidth | CWHeight)));

        if (c->x != px)
        {
            mask |= CWX;
        }
        if (c->y != py)
        {
            mask |= CWY;
        }
        if (c->width != pwidth)
        {
            mask |= CWWidth;
        }
        if (c->height != pheight)
        {
            mask |= CWHeight;
        }
    clientConfigureWindows (c, wc, mask, flags);
    /*

      We reparent to client window. According to the ICCCM spec, the
      WM must send a senthetic event when the window is moved and not resized.

      But, since we reparent the window, we must also send a synthetic
      configure event when the window is moved and resized.

      See this thread for the rational:
      http://www.mail-archive.com/wm-spec-list@gnome.org/msg00379.html

      And specifically this post from Carsten Haitzler:
      http://www.mail-archive.com/wm-spec-list@gnome.org/msg00382.html
     */
    if ((WIN_MOVED) || (flags & CFG_NOTIFY) ||
        ((flags & CFG_REQUEST) && !(WIN_MOVED || WIN_RESIZED)))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        DBG ("Sending ConfigureNotify");
        ce.type = ConfigureNotify;
        ce.display = clientGetXDisplay (c);
        ce.event = c->window;
        ce.window = c->window;
        ce.x = c->x;
        ce.y = c->y;
        ce.width = c->width;
        ce.height = c->height;
        ce.border_width = 0;
        ce.above = c->frame;
        ce.override_redirect = FALSE;
        XSendEvent (clientGetXDisplay (c), c->window, FALSE,
                    StructureNotifyMask, (XEvent *) & ce);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
#undef WIN_MOVED
#undef WIN_RESIZED
clientGetMWMHints (Client * c, gboolean update)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    DisplayInfo *display_info;
    PropMwmHints *mwm_hints;
    XWindowChanges wc;
    g_return_if_fail (c != NULL);
    g_return_if_fail (c->window != None);
    TRACE ("entering clientGetMWMHints client \"%s\" (0x%lx)", c->name,
    screen_info = c->screen_info;
    display_info = screen_info->display_info;

    mwm_hints = getMotifHints (display_info, c->window);
        if ((mwm_hints->flags & MWM_HINTS_DECORATIONS))
            if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_SHAPE))
                if (mwm_hints->decorations & MWM_DECOR_ALL)
                {
                    FLAG_SET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
                }
                else
                {
                    FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
                    FLAG_SET (c->xfwm_flags, (mwm_hints-> decorations & (MWM_DECOR_TITLE | MWM_DECOR_BORDER))
                    FLAG_SET (c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MENU))
                                             ? XFWM_FLAG_HAS_MENU : 0);
                    /*
                       FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
                       FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
                       FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MINIMIZE)) ? XFWM_FLAG_HAS_HIDE : 0);
                       FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MAXIMIZE)) ? XFWM_FLAG_HAS_MAXIMIZE : 0);
                     */
                }
            }
        }
        /* The following is from Metacity : */
        if (mwm_hints->flags & MWM_HINTS_FUNCTIONS)
        {
            if (!(mwm_hints->functions & MWM_FUNC_ALL))
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_UNSET (c->xfwm_flags,
                    XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
                    XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
                    XFWM_FLAG_HAS_RESIZE);
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_SET (c->xfwm_flags,
                    XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
                    XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
                    XFWM_FLAG_HAS_RESIZE);
            }

            if (mwm_hints->functions & MWM_FUNC_CLOSE)
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE);
            }
            if (mwm_hints->functions & MWM_FUNC_MINIMIZE)
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
            }
            if (mwm_hints->functions & MWM_FUNC_MAXIMIZE)
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
            }
            if (mwm_hints->functions & MWM_FUNC_RESIZE)
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_RESIZE);
            }
            if (mwm_hints->functions & MWM_FUNC_MOVE)
            {
Olivier Fourdan's avatar
Olivier Fourdan committed
                FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MOVE);
Olivier Fourdan's avatar
??  
Olivier Fourdan committed
        if (FLAG_TEST_ALL(c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_LEGACY_FULLSCREEN)
Olivier Fourdan's avatar
Olivier Fourdan committed
            && !FLAG_TEST(c->flags, CLIENT_FLAG_FULLSCREEN))
Olivier Fourdan's avatar
Olivier Fourdan committed
            /* legacy app changed its decoration, put it back on regular layer */
Olivier Fourdan's avatar
Olivier Fourdan committed
            FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_LEGACY_FULLSCREEN);
            clientSetLayer (c, WIN_LAYER_NORMAL);
        }
        wc.x = c->x;
        wc.y = c->y;
        wc.width = c->width;
        wc.height = c->height;
        clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_FORCE_REDRAW);

        /* MWM hints can add or remove decorations, update NET_FRAME_EXTENTS accordingly */
        setNetFrameExtents (display_info,
                            c->window,
                            frameTop (c),
                            frameLeft (c),
                            frameRight (c),
                            frameBottom (c));
    }
}

void
clientGetWMNormalHints (Client * c, gboolean update)
{
    XWindowChanges wc;
Olivier Fourdan's avatar
Olivier Fourdan committed
    unsigned long previous_value;
    long dummy;

    g_return_if_fail (c != NULL);
    g_return_if_fail (c->window != None);
    TRACE ("entering clientGetWMNormalHints client \"%s\" (0x%lx)", c->name,
        c->window);

    if (!c->size)
    {
        c->size = XAllocSizeHints ();
    }
    g_assert (c->size);
Olivier Fourdan's avatar
Olivier Fourdan committed

    dummy = 0;
    if (!XGetWMNormalHints (clientGetXDisplay (c), c->window, c->size, &dummy))
Olivier Fourdan's avatar
Olivier Fourdan committed
    previous_value = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
    FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);

    wc.x = c->x;
    wc.y = c->y;
    wc.width = c->width;
    wc.height = c->height;

    if (!(c->size->flags & PMaxSize))
        c->size->max_width = G_MAXINT;
        c->size->max_height = G_MAXINT;
        c->size->flags |= PMaxSize;
    }
    if (!(c->size->flags & PBaseSize))
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        c->size->base_width = 0;
        c->size->base_height = 0;
    if (!(c->size->flags & PMinSize))
    {
        if ((c->size->flags & PBaseSize))
            c->size->min_width = c->size->base_width;
            c->size->min_height = c->size->base_height;
            c->size->min_width = 1;
            c->size->min_height = 1;
        c->size->flags |= PMinSize;