Skip to content
Snippets Groups Projects
events.c 80 KiB
Newer Older
static void
handleButtonRelease (DisplayInfo *display_info, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleButtonRelease");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Avoid treating the same event twice */
    if (!check_button_time (ev))
    {
        TRACE ("ignoring ButtonRelease event because it has been already handled");
        return;
    }
    /* Get the screen structure from the root of the event */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    }

    XSendEvent (display_info->dpy, screen_info->xfwm4_win, FALSE, SubstructureNotifyMask, (XEvent *) ev);
static void
handleDestroyNotify (DisplayInfo *display_info, XDestroyWindowEvent * ev)
#ifdef ENABLE_KDE_SYSTRAY_PROXY
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleDestroyNotify");
    TRACE ("DestroyNotify on window (0x%lx)", ev->window);
    screen_info = myDisplayGetScreenFromSystray (display_info, ev->window);
    if  (screen_info)
        /* systray window is gone */
        screen_info->systray = None;
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        TRACE ("DestroyNotify for \"%s\" (0x%lx)", c->name, c->window);
        clientPassFocus (c->screen_info, c, c);
        clientUnframe (c, FALSE);
static void
handleMapRequest (DisplayInfo *display_info, XMapRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleMapRequest");
    TRACE ("MapRequest on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("Mapping None ???");
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        ScreenInfo *screen_info = c->screen_info;

Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientShow");
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
        {
            TRACE ("Ignoring MapRequest on window (0x%lx)", ev->window);
            return;
        }
        if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY) ||
            (c->win_workspace == screen_info->current_ws))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            clientFocusNew(c);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientFrame");
        clientFrame (display_info, ev->window, FALSE);
static void
handleMapNotify (DisplayInfo *display_info, XMapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleMapNotify");
    TRACE ("MapNotify on window (0x%lx)", ev->window);
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (c)
    {
        TRACE ("MapNotify for \"%s\" (0x%lx)", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
Olivier Fourdan's avatar
Olivier Fourdan committed
            FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_MAP_PENDING);
        compositorMapWindow (display_info, c->frame);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else if (myDisplayGetScreenFromRoot (display_info, ev->event))
    {
        compositorMapWindow (display_info, ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
static void
handleUnmapNotify (DisplayInfo *display_info, XUnmapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    Client *c = NULL;

    TRACE ("entering handleUnmapNotify");
    TRACE ("UnmapNotify on window (0x%lx)", ev->window);
        TRACE ("Ignoring UnmapNotify caused by parent's resize");
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (screen_info && (ev->event != ev->window) && (ev->event != screen_info->xroot || !ev->send_event))
        TRACE ("handleUnmapNotify (): Event ignored");
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
    if (c)
    {
        TRACE ("UnmapNotify for \"%s\" (0x%lx)", c->name, c->window);
        TRACE ("ignore_unmap for \"%s\" is %i", c->name, c->ignore_unmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
             * This UnmapNotify event is caused by reparenting
             * so we just ignore it, so the window won't return 
             * to withdrawn state by mistake.
             */
            TRACE ("Client \"%s\" is not mapped, event ignored", c->name);
Olivier Fourdan's avatar
Olivier Fourdan committed
        screen_info = c->screen_info;
        clientPassFocus (screen_info, c, c);
        compositorUnmapWindow (display_info, c->frame);
        
        /*
         * ICCCM spec states that a client wishing to switch
         * to WithdrawnState should send a synthetic UnmapNotify 
         * with the event field set to root if the client window 
         * is already unmapped.
         * Therefore, bypass the ignore_unmap counter and
         * unframe the client.
         */
        if ((ev->event == screen_info->xroot) && (ev->send_event))
        {
            TRACE ("ICCCM UnmapNotify for \"%s\"", c->name);
            clientUnframe (c, FALSE);
            return;
        }
        if (c->ignore_unmap)
        {
            c->ignore_unmap--;
            TRACE ("ignore_unmap for \"%s\" is now %i", 
Olivier Fourdan's avatar
Olivier Fourdan committed
            TRACE ("unmapping \"%s\" as ignore_unmap is %i", 
                 c->name, c->ignore_unmap);
            clientUnframe (c, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else
    {
        compositorUnmapWindow (display_info, ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
static gboolean
update_screen_idle_cb (gpointer data)
{
    ScreenInfo *screen_info = (ScreenInfo *) data;
    DisplayInfo *display_info = screen_info->display_info;
    
    setNetWorkarea (display_info, screen_info->xroot, screen_info->workspace_count, 
                    gdk_screen_get_width (screen_info->gscr),
                    gdk_screen_get_height (screen_info->gscr),
                    screen_info->margins);
    placeSidewalks (screen_info, screen_info->params->wrap_workspaces);
    clientScreenResize (screen_info);
    compositorUpdateScreenSize (screen_info);
static void
handleConfigureNotify (DisplayInfo *display_info, XConfigureEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    TRACE ("entering handleConfigureNotify");

    screen_info = myDisplayGetScreenFromRoot (display_info, ev->window);
    if (!screen_info)
    {
        return;
    }
    
    if (display_info->have_xrandr)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_RANDR
        XRRUpdateConfiguration ((XEvent *) ev);
#endif
    }
    else
        TRACE ("ConfigureNotify on the screen_info->xroot win (0x%lx)", ev->window);
        screen_info->xscreen->width  = ev->width;
        screen_info->xscreen->height = ev->height;
    /* 
       We need to use an idle function to update our screen layout to give gdk the
       time to update its internal structures, ie let the current event be processed
       by gdk otherwise the functions gdk_screen_get_width() and gdk_screen_get_height()
       don't return accurate values...
     */
    g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, update_screen_idle_cb, screen_info, NULL);
static void
handleConfigureRequest (DisplayInfo *display_info, XConfigureRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    XWindowChanges wc;
Olivier Fourdan's avatar
Olivier Fourdan committed
    XEvent otherEvent;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleConfigureRequest");
    TRACE ("ConfigureRequest on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    /* Compress events - logic taken from kwin */
    while (XCheckTypedWindowEvent (display_info->dpy, ev->window, ConfigureRequest, &otherEvent))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        /* Update the display time */
        myDisplayUpdateCurentTime (display_info, &otherEvent);

        if (otherEvent.xconfigurerequest.value_mask == ev->value_mask)
        {
            ev = &otherEvent.xconfigurerequest;
        }
        else
        {
            XPutBackEvent (display_info->dpy, &otherEvent);
Olivier Fourdan's avatar
Olivier Fourdan committed
    wc.x = ev->x;
    wc.y = ev->y;
    wc.width = ev->width;
    wc.height = ev->height;
    wc.sibling = ev->above;
    wc.stack_mode = ev->detail;
    wc.border_width = ev->border_width;

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        /* Some app tend or try to manipulate the wm frame to achieve fullscreen mode */
        c = myDisplayGetClientFromWindow (display_info, ev->window, FRAME);
            TRACE ("client %s (0x%lx) is attempting to manipulate its frame!", c->name, c->window);
            if (ev->value_mask & CWX)
            {
                wc.x += frameLeft (c);
            }
            if (ev->value_mask & CWY)
            {
                wc.y += frameTop (c);
            }
            if (ev->value_mask & CWWidth)
            {
                wc.width -= frameLeft (c) + frameRight (c);
            }
            if (ev->value_mask & CWHeight)
            {
                wc.height -= frameTop (c) + frameBottom (c);
            }
            /* We don't allow changing stacking order by accessing the frame
               window because that would break the layer management in xfwm4
             */
            ev->value_mask &= ~(CWSibling | CWStackMode);
        }
        gboolean constrained = FALSE;
        ScreenInfo *screen_info = c->screen_info;
        TRACE ("handleConfigureRequest managed window \"%s\" (0x%lx)", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
        {
            /* Sorry, but it's not the right time for configure request */
            return;
        }
        if (c->type == WINDOW_DESKTOP)
        {
            /* Ignore stacking request for DESKTOP windows */
            ev->value_mask &= ~(CWSibling | CWStackMode);
        }
        clientCoordGravitate (c, APPLY, &wc.x, &wc.y);
        if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
        {
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            int cx, cy;

            /* size request from fullscreen windows get fullscreen */
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            cx = frameX (c) + (frameWidth (c) / 2);
            cy = frameY (c) + (frameHeight (c) / 2);

            monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
            gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);

            wc.x = rect.x;
            wc.y = rect.y;
            wc.width = rect.width;
            wc.height = rect.height;
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed

            ev->value_mask |= (CWX | CWY | CWWidth | CWHeight);
        }
        /* Clean up buggy requests that set all flags */
        if ((ev->value_mask & CWX) && (wc.x == c->x))
        {
            ev->value_mask &= ~CWX;
        }
        if ((ev->value_mask & CWY) && (wc.y == c->y))
        {
            ev->value_mask &= ~CWY;
        }
        if ((ev->value_mask & CWWidth) && (wc.width == c->width))
        {
            ev->value_mask &= ~CWWidth;
        }
        if ((ev->value_mask & CWHeight) && (wc.height == c->height))
        {
            ev->value_mask &= ~CWHeight;
        }
        /* Still a move/resize after cleanup? */
        if (ev->value_mask & (CWX | CWY | CWWidth | CWHeight))
        {
            if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
            {
                clientRemoveMaximizeFlag (c);
            }
            constrained = TRUE;
        }
        if (ev->value_mask & CWStackMode)
        {
        /* Let's say that if the client performs a XRaiseWindow, we show the window if hidden */
        if ((ev->value_mask & CWStackMode) && (wc.stack_mode == Above))
        {
            if ((c->win_workspace == screen_info->current_ws) || 
                (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY)))
                if (FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
                    clientClearAllShowDesktop (screen_info);
        clientConfigure (c, &wc, ev->value_mask, (constrained ? CFG_CONSTRAINED : 0) | CFG_REQUEST);
        TRACE ("unmanaged configure request for win 0x%lx", ev->window);
        XConfigureWindow (display_info->dpy, ev->window, ev->value_mask, &wc);
static void
handleEnterNotify (DisplayInfo *display_info, XCrossingEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    static Time lastresist = (Time) 0;
    gboolean warp_pointer = FALSE;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleEnterNotify");
Olivier Fourdan's avatar
Olivier Fourdan committed

    if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)
        || (ev->detail > NotifyNonlinearVirtual))
        /* We're not interested in such notifications */
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("EnterNotify on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = myDisplayGetClientFromWindow (display_info, ev->window, FRAME);
    if (c)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        screen_info = c->screen_info;
        
        if (!(screen_info->params->click_to_focus) && clientAcceptFocus (c))
            TRACE ("EnterNotify window is \"%s\"", c->name);
            if (!(c->type & (WINDOW_DOCK | WINDOW_DESKTOP)))
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientSetFocus (c->screen_info, c, ev->time, NO_FOCUS_FLAG);
        
        /* No need to process the event any further */
        return;
    }
    
    /* The event was not for a client window */

    if (display_info->nb_screens > 1)
    {
        /* Wrap workspace/wrap windows is disabled with multiscreen */
        return;
    }
    
    /* Get the screen structure from the root of the event */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);

    if (!screen_info)
    {
        return;
    }
    
    if (screen_info->workspace_count && screen_info->params->wrap_workspaces
        && screen_info->params->wrap_resistance)
    {
        int msx, msy, maxx, maxy;
        int rx, ry;

        msx = ev->x_root;
        msy = ev->y_root;
        maxx = gdk_screen_get_width (screen_info->gscr) - 1;
        maxy = gdk_screen_get_height (screen_info->gscr) - 1;
            if ((ev->time - lastresist) > 250)  /* ms */
            {
                edge_scroll_x = 0;
            }
            else
            {
                edge_scroll_x++;
            }
            warp_pointer = TRUE;
            lastresist = ev->time;
        }
        if ((msy == 0) || (msy == maxy))
        {
            if ((ev->time - lastresist) > 250)  /* ms */
            {
                edge_scroll_y = 0;
            }
            else
            {
                edge_scroll_y++;
            }
            if (msy == 0) 
            {
            warp_pointer = TRUE;
        if (edge_scroll_x > screen_info->params->wrap_resistance)
        {
                if (workspaceMove (screen_info, 0, -1, NULL))
                {
                    rx = 4 * maxx / 5;
                if (workspaceMove (screen_info, 0, 1, NULL))
                {
                    rx = -4 * maxx / 5;
        }
        if (edge_scroll_y > screen_info->params->wrap_resistance)
        {
            edge_scroll_y = 0;
                if (workspaceMove (screen_info, -1, 0, NULL))
                {
                    ry = 4 * maxy / 5;
            {
                if (workspaceMove (screen_info, 1, 0, NULL))
                {
                    ry = -4 * maxy / 5;
            warp_pointer = TRUE;
        }
        if (warp_pointer)
        {
            XWarpPointer (display_info->dpy, None, None, 0, 0, 0, 0, rx, ry);
            XFlush (display_info->dpy);
static void
handleLeaveNotify (DisplayInfo *display_info, XCrossingEvent * ev)
    TRACE ("entering handleLeaveNotify");
static void
handleFocusIn (DisplayInfo *display_info, XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    Client *last_raised = NULL;
        
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleFocusIn");
    TRACE ("handleFocusIn (0x%lx) mode = %s",
Olivier Fourdan's avatar
Olivier Fourdan committed
                ev->window,
                (ev->mode == NotifyNormal) ?
                "NotifyNormal" :
                (ev->mode == NotifyWhileGrabbed) ?
                "NotifyWhileGrabbed" :
                "(unknown)");
    TRACE ("handleFocusIn (0x%lx) detail = %s",
Olivier Fourdan's avatar
Olivier Fourdan committed
                ev->window,
                (ev->detail == NotifyAncestor) ?
                "NotifyAncestor" :
                (ev->detail == NotifyVirtual) ?
                "NotifyVirtual" :
                (ev->detail == NotifyInferior) ?
                "NotifyInferior" :
                (ev->detail == NotifyNonlinear) ?
                "NotifyNonlinear" :
                (ev->detail == NotifyNonlinearVirtual) ?
                "NotifyNonlinearVirtual" :
                (ev->detail == NotifyPointer) ?
                "NotifyPointer" :
                (ev->detail == NotifyPointerRoot) ?
                "NotifyPointerRoot" :
                (ev->detail == NotifyDetailNone) ?
                "NotifyDetailNone" :
                "(unknown)");
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (screen_info && (ev->window == screen_info->xroot) && (ev->mode == NotifyNormal) && 
        /* Handle focus transition to root (means that an unknown
           window has vanished and the focus is returned to the root
            clientSetFocus (c->screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
    
    if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab) ||
        /* We're not interested in such notifications */
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
    TRACE ("FocusIn on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("focus set to \"%s\" (0x%lx)", c->name, c->window);
        screen_info = c->screen_info;
        clientUpdateFocus (screen_info, c, FOCUS_SORT);
        last_raised = clientGetLastRaise (screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if ((screen_info->params->click_to_focus) && 
            (screen_info->params->raise_on_click) && 
            (last_raised != NULL) && (c != last_raised))
        if (screen_info->params->raise_on_focus)
            reset_timeout (screen_info);
static void
handleFocusOut (DisplayInfo *display_info, XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering handleFocusOut");
Olivier Fourdan's avatar
Olivier Fourdan committed
    TRACE ("handleFocusOut (0x%lx) mode = %s",
                ev->window,
                (ev->mode == NotifyNormal) ?
                "NotifyNormal" :
                (ev->mode == NotifyWhileGrabbed) ?
                "NotifyWhileGrabbed" :
                "(unknown)");
    TRACE ("handleFocusOut (0x%lx) detail = %s",
                ev->window,
                (ev->detail == NotifyAncestor) ?
                "NotifyAncestor" :
                (ev->detail == NotifyVirtual) ?
                "NotifyVirtual" :
                (ev->detail == NotifyInferior) ?
                "NotifyInferior" :
                (ev->detail == NotifyNonlinear) ?
                "NotifyNonlinear" :
                (ev->detail == NotifyNonlinearVirtual) ?
                "NotifyNonlinearVirtual" :
                (ev->detail == NotifyPointer) ?
                "NotifyPointer" :
                (ev->detail == NotifyPointerRoot) ?
                "NotifyPointerRoot" :
                (ev->detail == NotifyDetailNone) ?
                "NotifyDetailNone" :
                "(unknown)");
    if ((ev->mode == NotifyNormal)
        && ((ev->detail == NotifyNonlinear) 
            || (ev->detail == NotifyNonlinearVirtual)))
        c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        TRACE ("FocusOut on window (0x%lx)", ev->window);
        {
            TRACE ("focus lost from \"%s\" (0x%lx)", c->name, c->window);
            clientUpdateFocus (c->screen_info, NULL, NO_FOCUS_FLAG);
            /* Clear timeout */
            clear_timeout ();
        }
static void
handlePropertyNotify (DisplayInfo *display_info, XPropertyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handlePropertyNotify");

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        screen_info = c->screen_info;
        if (ev->atom == XA_WM_NORMAL_HINTS)
        {
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_NORMAL_HINTS notify", c->name, c->window);
            clientGetWMNormalHints (c, TRUE);
        else if ((ev->atom == XA_WM_NAME) || 
                 (ev->atom == display_info->atoms[NET_WM_NAME]) || 
                 (ev->atom == display_info->atoms[WM_CLIENT_MACHINE]))
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_NAME/NET_WM_NAME/WM_CLIENT_MACHINE notify", c->name, c->window);
            getWindowName (display_info, c->window, &c->name);
            FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
            frameDraw (c, TRUE, FALSE);
        }
        else if (ev->atom == display_info->atoms[MOTIF_WM_HINTS])
            TRACE ("client \"%s\" (0x%lx) has received a motif_wm_hints notify", c->name, c->window);
            clientGetMWMHints (c, TRUE);
        }
        else if (ev->atom == XA_WM_HINTS)
        {
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_HINTS notify", c->name, c->window);
            c->wmhints = XGetWMHints (display_info->dpy, c->window);
                if (c->wmhints->flags & WindowGroupHint)
                {
                    c->group_leader = c->wmhints->window_group;
                }
                if ((c->wmhints->flags & IconPixmapHint) && (screen_info->params->show_app_icon))
                {
                    clientUpdateIcon (c);
                    frameDraw (c, TRUE, FALSE);
                }
            clientUpdateUrgency (c);
        else if (ev->atom == display_info->atoms[WM_PROTOCOLS])
            TRACE ("client \"%s\" (0x%lx) has received a wm_protocols notify", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientGetWMProtocols (c);
        }
        else if (ev->atom == display_info->atoms[WM_TRANSIENT_FOR])
            TRACE ("client \"%s\" (0x%lx) has received a wm_transient_for notify", c->name, c->window);
            getTransientFor (display_info, c->screen_info->xroot, c->window, &w);
            if (clientCheckTransientWindow (c, w))
            {
                c->transient_for = w;
        else if (ev->atom == display_info->atoms[WIN_HINTS])
            TRACE ("client \"%s\" (0x%lx) has received a win_hints notify", c->name, c->window);
            getHint (display_info, c->window, WIN_HINTS, (long *) &c->win_hints);
        else if (ev->atom == display_info->atoms[NET_WM_WINDOW_TYPE])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_window_type notify", c->name, c->window);
            clientGetNetWmType (c);
            frameDraw (c, TRUE, FALSE);
        }
        else if ((ev->atom == display_info->atoms[NET_WM_STRUT]) || 
                 (ev->atom == display_info->atoms[NET_WM_STRUT_PARTIAL]))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_strut notify", c->name, c->window);
        else if (ev->atom == display_info->atoms[WM_COLORMAP_WINDOWS])
            TRACE ("client \"%s\" (0x%lx) has received a wm_colormap_windows notify", c->name, c->window);
            clientUpdateColormaps (c);
            if (c == clientGetFocus ())
            {
                clientInstallColormaps (c);
            }
        }
        else if (ev->atom == display_info->atoms[NET_WM_USER_TIME])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_user_time notify", c->name, c->window);
            if (getNetWMUserTime (display_info, c->window, &c->user_time))
                FLAG_SET (c->flags, CLIENT_FLAG_HAS_USER_TIME);
        else if (ev->atom == display_info->atoms[NET_WM_WINDOW_OPACITY])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_opacity notify", c->name, c->window);
            if (!getOpacity (display_info, c->window, &c->opacity))
                c->opacity =  NET_WM_OPAQUE;
            compositorWindowSetOpacity (display_info, c->frame, c->opacity);
        else if ((screen_info->params->show_app_icon) &&
                 ((ev->atom == display_info->atoms[NET_WM_ICON]) ||
                  (ev->atom == display_info->atoms[KWM_WIN_ICON])))
        {
            clientUpdateIcon (c);
            frameDraw (c, TRUE, FALSE);
        }
#ifdef HAVE_STARTUP_NOTIFICATION
        else if (ev->atom == display_info->atoms[NET_STARTUP_ID])
            getWindowStartupId (display_info, c->window, &c->startup_id);
        return;
    }
    
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (!screen_info)
    {
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    if (ev->atom == display_info->atoms[NET_DESKTOP_NAMES])
        TRACE ("root has received a net_desktop_names notify");
        if (getUTF8StringList (display_info, screen_info->xroot, NET_DESKTOP_NAMES, &names, &items))
            workspaceSetNames (screen_info, names, items);
    else if (ev->atom == display_info->atoms[GNOME_PANEL_DESKTOP_AREA])
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("root has received a gnome_panel_desktop_area notify");
        getGnomeDesktopMargins (display_info, screen_info->xroot, screen_info->gnome_margins);
        workspaceUpdateArea (screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else if (ev->atom == display_info->atoms[NET_DESKTOP_LAYOUT])
    {
        TRACE ("root has received a net_desktop_layout notify");
        getDesktopLayout(display_info, screen_info->xroot, screen_info->workspace_count, &screen_info->desktop_layout);
        placeSidewalks(screen_info, screen_info->params->wrap_workspaces);
static void
handleClientMessage (DisplayInfo *display_info, XClientMessageEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean is_transient = FALSE;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleClientMessage");

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        screen_info = c->screen_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
        is_transient = clientIsValidTransientOrModal (c);
        if ((ev->message_type == display_info->atoms[WM_CHANGE_STATE]) && (ev->format == 32) && (ev->data.l[0] == IconicState))
            TRACE ("client \"%s\" (0x%lx) has received a wm_change_state event", c->name, c->window);
            if (!FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED) &&  CLIENT_CAN_HIDE_WINDOW (c))
            {
                clientHide (c, c->win_workspace, TRUE);
            }
        }
        else if ((ev->message_type == display_info->atoms[WIN_STATE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_state event", c->name, c->window);
            clientUpdateWinState (c, ev);
        }
        else if ((ev->message_type == display_info->atoms[WIN_LAYER]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_layer event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if ((ev->data.l[0] != c->win_layer) && !is_transient)
            {
                clientSetLayer (c, ev->data.l[0]);
            }
        }
        else if ((ev->message_type == display_info->atoms[WIN_WORKSPACE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_workspace event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if ((ev->data.l[0] != c->win_workspace) && !is_transient)
            {
                clientSetWorkspace (c, ev->data.l[0], TRUE);
            }
        }
        else if ((ev->message_type == display_info->atoms[NET_WM_DESKTOP]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_desktop event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (!is_transient)
            {
                if (ev->data.l[0] == ALL_WORKSPACES)
                {
                    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK) && !FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
                    {
                        clientStick (c, TRUE);
                        frameDraw (c, FALSE, FALSE);
                    }
                }
                else
                {
                    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK) && FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
                    {
                        clientUnstick (c, TRUE);
                        frameDraw (c, FALSE, FALSE);
                    }
                    if (ev->data.l[0] != c->win_workspace)
                    {
                        clientSetWorkspace (c, ev->data.l[0], TRUE);
                    }
                }
            }
        }
        else if ((ev->message_type == display_info->atoms[NET_CLOSE_WINDOW]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_close_window event", c->name, c->window);
        else if ((ev->message_type == display_info->atoms[NET_WM_STATE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_state event", c->name, c->window);
            clientUpdateNetState (c, ev);
        }
        else if ((ev->message_type == display_info->atoms[NET_WM_MOVERESIZE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_moveresize event", c->name, c->window);
            g_warning ("Operation not supported (yet)");
        else if ((ev->message_type == display_info->atoms[NET_ACTIVE_WINDOW]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_active_window event", c->name, c->window);
            if (ev->data.l[0] != 0)
            {
                Time current = myDisplayGetCurrentTime (screen_info->display_info);
                Time ev_time = (Time) ev->data.l[1];

                /* We are simply ignoring XServer time wraparound here */
                TRACE ("Time of event received is %u, current XServer time is %u", (unsigned int) ev_time, (unsigned int) current);
                if ((ev_time != (Time) 0) && (ev_time < current))
                {
                    FLAG_SET (c->flags, CLIENT_FLAG_DEMANDS_ATTENTION);
                    clientSetNetState (c);
                }
                else
                {
                    clientSetWorkspace (c, screen_info->current_ws, TRUE);
                    clientShow (c, TRUE);
                    clientClearAllShowDesktop (screen_info);
                    clientRaise (c, None);
                    clientSetFocus (screen_info, c, (Time) ev_time, NO_FOCUS_FLAG);
                }
                clientSetWorkspace (c, screen_info->current_ws, TRUE);
                clientShow (c, TRUE);
                clientClearAllShowDesktop (screen_info);
                clientRaise (c, None);
                clientSetFocus (screen_info, c, CurrentTime, NO_FOCUS_FLAG);
            }
        else if (ev->message_type == display_info->atoms[NET_REQUEST_FRAME_EXTENTS])
        {
            TRACE ("client \"%s\" (0x%lx) has received a net_request_frame_extents event", c->name, c->window);
            setNetFrameExtents (display_info, c->window, frameTop (c), frameLeft (c),
                                                         frameRight (c), frameBottom (c)); 
        screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
        if (!screen_info)
        {
            return;
        }
        
        if (((ev->message_type == display_info->atoms[WIN_WORKSPACE]) || 
             (ev->message_type == display_info->atoms[NET_CURRENT_DESKTOP])) && (ev->format == 32))