Skip to content
Snippets Groups Projects
events.c 56.9 KiB
Newer Older
Olivier Fourdan's avatar
Olivier Fourdan committed
    wc.width = ev->width;
    wc.height = ev->height;
    wc.sibling = ev->above;
    wc.stack_mode = ev->detail;
    wc.border_width = ev->border_width;

    c = clientGetFromWindow (ev->window, WINDOW);
    if (!c)
    {
        /* Some app tend or try to manipulate the wm frame to achieve fullscreen mode */
        c = clientGetFromWindow (ev->window, FRAME);
        if (c)
        {
            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;

        TRACE ("handleConfigureRequest managed window \"%s\" (0x%lx)",
            c->name, c->window);
        if (FLAG_TEST (c->flags, CLIENT_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
        {
            int cx, cy;

            /* size request from fullscreen windows get fullscreen */
            
            cx = frameX (c) + (frameWidth (c) / 2);
            cy = frameY (c) + (frameHeight (c) / 2);

            wc.x = MyDisplayX (cx, cy);
            wc.y = MyDisplayY (cx, cy);
            wc.width = MyDisplayWidth (dpy, screen, cx, cy);
            wc.height = MyDisplayHeight (dpy, screen, cx, cy);

            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)
        {
	    clientPassGrabButton1 (NULL);
	}
        /* 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 == workspace) || 
                (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY)))
                if (FLAG_TEST (c->flags, CLIENT_FLAG_HIDDEN))
        clientConfigure (c, &wc, ev->value_mask, 
                         (constrained ? CFG_CONSTRAINED : 0) | CFG_REQUEST);
        TRACE ("unmanaged configure request for win 0x%lx", ev->window);
        XConfigureWindow (dpy, ev->window, ev->value_mask, &wc);
static void
handleEnterNotify (XCrossingEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
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 = clientGetFromWindow (ev->window, FRAME);
    if (c && !(params.click_to_focus) && (clientAcceptFocus (c)))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("EnterNotify window is \"%s\"", c->name);
        if (!(c->type & (WINDOW_DOCK | WINDOW_DESKTOP)))
            clientSetFocus (c, FOCUS_FORCE);
                clientPassGrabButton1 (c);
static void
handleLeaveNotify (XCrossingEvent * ev)
    TRACE ("entering handleLeaveNotify");
    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
    if ((ev->window == sidewalk[0]) || (ev->window == sidewalk[1]))
static void
handleFocusIn (XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
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)");
    if ((ev->window == root) && (ev->mode == NotifyNormal) && 
        (ev->detail == NotifyDetailNone))
    {
        /* Handle focus transition to root (means that an unknown
           window has vanished and the focus is returned to the root
         */
        c = clientGetFocus ();
        if (c)
        {
            clientSetFocus (c, FOCUS_FORCE);
        }
        return;
    }
    else 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

    c = clientGetFromWindow (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);
        clientUpdateFocus (c, FOCUS_SORT);
        if (params.raise_on_focus && !params.click_to_focus)
        {
            reset_timeout ();
        }
static void
handleFocusOut (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 = clientGetFromWindow (ev->window, WINDOW);
        TRACE ("FocusOut on window (0x%lx)", ev->window);
        {
            TRACE ("focus lost from \"%s\" (0x%lx)", c->name, c->window);
            clientUpdateFocus (NULL, NO_FOCUS_FLAG);
            /* Clear timeout */
            clear_timeout ();
        }
static void
handlePropertyNotify (XPropertyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handlePropertyNotify");

    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
    {
        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 == net_wm_name))
        {
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_NAME notify",
                c->name, c->window);
            if (c->name)
            {
                free (c->name);
            }
            getWindowName (dpy, c->window, &c->name);
            FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
            frameDraw (c, TRUE, FALSE);
        }
        else if (ev->atom == 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 (dpy, c->window);
            if (c->wmhints)
            {
                if (c->wmhints->flags & WindowGroupHint)
                {
                    c->group_leader = c->wmhints->window_group;
                }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if (ev->atom == wm_protocols)
        {
            TRACE
                ("client \"%s\" (0x%lx) has received a wm_protocols notify",
                c->name, c->window);
            clientGetWMProtocols (c);
        }
        else if (ev->atom == win_hints)
        {
            TRACE ("client \"%s\" (0x%lx) has received a win_hints notify",
                c->name, c->window);
            getHint (dpy, c->window, win_hints, &c->win_hints);
        }
        else if (ev->atom == 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);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if ((ev->atom == net_wm_strut) || (ev->atom == net_wm_strut_partial))
        {
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_strut notify",
                c->name, c->window);
            clientGetNetStruts (c);
        }
        else if (ev->atom == wm_colormap_windows)
        {
            clientUpdateColormaps (c);
            if (c == clientGetFocus ())
            {
                clientInstallColormaps (c);
            }
        }
#ifdef HAVE_STARTUP_NOTIFICATION
        else if (ev->atom == net_startup_id)
        {
            if (c->startup_id)
            {
                free (c->startup_id);
                c->startup_id = NULL;
            }
            getWindowStartupId (dpy, c->window, &c->startup_id);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else if (ev->atom == net_desktop_names)
    {
        TRACE ("root has received a net_desktop_names notify");
        if (get_utf8_string (dpy, root, net_desktop_names, &names, &length))
        {
            workspaceSetNames (names, length);
        }
    }
    else if (ev->atom == gnome_panel_desktop_area)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("root has received a gnome_panel_desktop_area notify");
        getGnomeDesktopMargins (dpy, screen, gnome_margins);
        workspaceUpdateArea (margins, gnome_margins);
static void
handleClientMessage (XClientMessageEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleClientMessage");

Olivier Fourdan's avatar
Olivier Fourdan committed
    /* Don't get surprised with the multiple "if (!clientIsTransientOrModal(c))" tests
       xfwm4 really treats transient differently
     */

    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
    {
        if ((ev->message_type == 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_HIDDEN) && 
                 CLIENT_CAN_HIDE_WINDOW (c))
            {
                clientHide (c, c->win_workspace, TRUE);
            }
        }
        else if ((ev->message_type == 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 == 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) && !clientIsTransientOrModal (c))
            {
                clientSetLayer (c, ev->data.l[0]);
                clientSetNetState (c);
            }
        }
        else if ((ev->message_type == 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) && !clientIsTransientOrModal (c))
            {
                clientSetWorkspace (c, ev->data.l[0], TRUE);
            }
        }
        else if ((ev->message_type == 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 (!clientIsTransientOrModal (c))
            {
                if (ev->data.l[0] == ALL_WORKSPACES)
                {
                    if (FLAG_TEST_AND_NOT (c->flags, CLIENT_FLAG_HAS_STICK,
                            CLIENT_FLAG_STICKY))
                    {
                        clientStick (c, TRUE);
                        frameDraw (c, FALSE, FALSE);
                    }
                }
                else
                {
                    if (FLAG_TEST_ALL (c->flags,
                            CLIENT_FLAG_HAS_STICK | 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 == net_close_window) && (ev->format == 32))
        {
            TRACE
                ("client \"%s\" (0x%lx) has received a net_close_window event",
                c->name, c->window);
            clientClose (c);
        }
        else if ((ev->message_type == 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 == net_wm_moveresize)
            && (ev->format == 32))
        {
            TRACE
                ("client \"%s\" (0x%lx) has received a net_wm_moveresize event",
                c->name, c->window);
            g_message (_("%s: Operation not supported (yet)\n"),
                g_get_prgname ());
            /* TBD */
        }
        else if ((ev->message_type == net_active_window)
            && (ev->format == 32))
        {
            TRACE
                ("client \"%s\" (0x%lx) has received a net_active_window event",
                c->name, c->window);
            clientSetWorkspace (c, workspace, TRUE);
            clientShow (c, TRUE);
            clientRaise (c);
            clientSetFocus (c, NO_FOCUS_FLAG);
            clientPassGrabButton1 (c);
        if (((ev->message_type == win_workspace)
                || (ev->message_type == net_current_desktop))
            && (ev->format == 32))
        {
            TRACE
                ("root has received a win_workspace or a net_current_desktop event");
            if (ev->data.l[0] != workspace)
            {
                workspaceSwitch (ev->data.l[0], NULL);
            }
        }
        else if (((ev->message_type == win_workspace_count)
                || (ev->message_type == net_number_of_desktops))
            && (ev->format == 32))
        {
            TRACE ("root has received a win_workspace_count event");
            if (ev->data.l[0] != params.workspace_count)
            {
                workspaceSetCount (ev->data.l[0]);
            }
        }
        else if ((ev->message_type == net_system_tray_manager)
                  && (ev->data.l[1] == net_system_tray_selection)
                  && (ev->format == 32))
        {
            TRACE ("root has received a net_system_tray_manager event");
            systray = getSystrayWindow (dpy);
        }
        else
        {
            TRACE ("unidentified client message for window 0x%lx",
                ev->window);
        }
static void
handleShape (XShapeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

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

    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        frameDraw (c, FALSE, TRUE);
static void
handleColormapNotify (XColormapEvent * ev)
    TRACE ("entering handleColormapNotify");
    c = clientGetFromWindow (ev->window, WINDOW);
    if ((c) && (ev->window == c->window) && (ev->new))
        if (c == clientGetFocus ())
        {
            clientInstallColormaps (c);
        }
void
handleEvent (XEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering handleEvent");
Olivier Fourdan's avatar
Olivier Fourdan committed

    last_timestamp = stashEventTime (last_timestamp, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    switch (ev->type)
    {
        case MotionNotify:
            handleMotionNotify ((XMotionEvent *) ev);
            break;
        case KeyPress:
            handleKeyPress ((XKeyEvent *) ev);
            break;
        case ButtonPress:
            handleButtonPress ((XButtonEvent *) ev);
            break;
        case ButtonRelease:
            handleButtonRelease ((XButtonEvent *) ev);
            break;
        case DestroyNotify:
            handleDestroyNotify ((XDestroyWindowEvent *) ev);
            break;
        case UnmapNotify:
            handleUnmapNotify ((XUnmapEvent *) ev);
            break;
        case MapRequest:
            handleMapRequest ((XMapRequestEvent *) ev);
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
        case MapNotify:
            handleMapNotify ((XMapEvent *) ev);
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
        case ConfigureNotify:
            handleConfigureNotify ((XConfigureEvent *) ev);
            break;
        case ConfigureRequest:
            handleConfigureRequest ((XConfigureRequestEvent *) ev);
            break;
        case EnterNotify:
            handleEnterNotify ((XCrossingEvent *) ev);
            break;
        case LeaveNotify:
            handleLeaveNotify ((XCrossingEvent *) ev);
            break;
        case FocusIn:
            handleFocusIn ((XFocusChangeEvent *) ev);
            break;
        case FocusOut:
            handleFocusOut ((XFocusChangeEvent *) ev);
            break;
        case PropertyNotify:
            handlePropertyNotify ((XPropertyEvent *) ev);
            break;
        case ClientMessage:
            handleClientMessage ((XClientMessageEvent *) ev);
            break;
        case ColormapNotify:
            handleColormapNotify ((XColormapEvent *) ev);
            break;
        default:
            if (shape && (ev->type == shape_event))
            {
                handleShape ((XShapeEvent *) ev);
            }
    }
    if (!gdk_events_pending () && !XPending (dpy))
    {
        if (reload)
        {
            reloadSettings (UPDATE_ALL);
            reload = FALSE;
        }
        else if (quit)
        {
            gtk_main_quit ();
        }
GtkToXEventFilterStatus
xfwm4_event_filter (XEvent * xevent, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering xfwm4_event_filter");
    handleEvent (xevent);
    TRACE ("leaving xfwm4_event_filter");
Olivier Fourdan's avatar
Olivier Fourdan committed
    return XEV_FILTER_STOP;
}

Olivier Fourdan's avatar
Olivier Fourdan committed

static void
menu_callback (Menu * menu, MenuOp op, Window client_xwindow,
    gpointer menu_data, gpointer item_data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c = NULL;
    TRACE ("entering menu_callback");
        removeTmpEventWin (menu_event_window);
        menu_event_window = None;
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        c = (Client *) menu_data;
        c = clientGetFromWindow (c->window, WINDOW);
        if (!c)
        {
            menu_free (menu);
            return;
        }
        c->button_pressed[MENU_BUTTON] = FALSE;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    switch (op)
    {
        case MENU_OP_QUIT:
            gtk_main_quit ();
            break;
        case MENU_OP_MAXIMIZE:
        case MENU_OP_UNMAXIMIZE:
            if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
            {
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
            }
            break;
        case MENU_OP_MINIMIZE:
            if (CLIENT_CAN_HIDE_WINDOW (c))
            {
                clientHide (c, c->win_workspace, TRUE);
            }
            frameDraw (c, FALSE, FALSE);
            break;
        case MENU_OP_MINIMIZE_ALL:
            clientHideAll (c, c->win_workspace);
            frameDraw (c, FALSE, FALSE);
            break;
        case MENU_OP_UNMINIMIZE:
            clientShow (c, TRUE);
            break;
        case MENU_OP_SHADE:
        case MENU_OP_UNSHADE:
            clientToggleShaded (c);
            break;
        case MENU_OP_STICK:
        case MENU_OP_UNSTICK:
            clientToggleSticky (c, TRUE);
            frameDraw (c, FALSE, FALSE);
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
        case MENU_OP_WORKSPACES:
            clientSetWorkspace (c, GPOINTER_TO_INT (item_data), TRUE);
            frameDraw (c, FALSE, FALSE);
            break;
        case MENU_OP_DELETE:
            frameDraw (c, FALSE, FALSE);
            clientClose (c);
            break;
        case MENU_OP_CONTEXT_HELP:
            clientEnterContextMenuState (c);
            frameDraw (c, FALSE, FALSE);
            break;
        case MENU_OP_ABOVE:
        case MENU_OP_NORMAL:
        default:
            frameDraw (c, FALSE, FALSE);
            break;
static gboolean
show_popup_cb (GtkWidget * widget, GdkEventButton * ev, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Menu *menu;
    MenuOp ops;
    MenuOp insensitive;
    Client *c = NULL;
    gint x = ev->x_root;
    gint y = ev->y_root;

    TRACE ("entering show_popup_cb");

    if (((ev->button == 1) || (ev->button == 3)) && (c = (Client *) data))
    {
        c->button_pressed[MENU_BUTTON] = TRUE;
        frameDraw (c, FALSE, FALSE);
        y = c->y;
Olivier Fourdan's avatar
Olivier Fourdan committed
        ops = MENU_OP_DELETE | MENU_OP_MINIMIZE_ALL | MENU_OP_WORKSPACES;
        if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_CLOSE))
        if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
        {
            ops |= MENU_OP_UNMAXIMIZE;
            if (!CLIENT_CAN_MAXIMIZE_WINDOW (c))
            {
                insensitive |= MENU_OP_UNMAXIMIZE;
            }
        }
        else
        {
            ops |= MENU_OP_MAXIMIZE;
            if (!CLIENT_CAN_MAXIMIZE_WINDOW (c))
            {
                insensitive |= MENU_OP_MAXIMIZE;
            }
        }

        if (FLAG_TEST (c->flags, CLIENT_FLAG_HIDDEN))
        {
            ops |= MENU_OP_UNMINIMIZE;
            if (!CLIENT_CAN_HIDE_WINDOW (c))
            {
                insensitive |= MENU_OP_UNMINIMIZE;
            }
        }
        else
        {
            ops |= MENU_OP_MINIMIZE;
            if (!CLIENT_CAN_HIDE_WINDOW (c))
            {
                insensitive |= MENU_OP_MINIMIZE;
            }
        }

        if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
        {
            ops |= MENU_OP_UNSHADE;
        }
        else
        {
            ops |= MENU_OP_SHADE;
        }

        if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
            if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STICK))
            {
                insensitive |= MENU_OP_UNSTICK;
            }
        }
        else
        {
            ops |= MENU_OP_STICK;
            if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STICK))
    
        /* KDE extension */
        clientGetWMProtocols(c);
        if (FLAG_TEST (c->wm_flags, WM_FLAG_CONTEXT_HELP))
        {
            ops |= MENU_OP_CONTEXT_HELP;
        }
        if (FLAG_TEST(c->flags, CLIENT_FLAG_ABOVE))
                FLAG_TEST (c->flags, CLIENT_FLAG_BELOW | CLIENT_FLAG_FULLSCREEN))
                FLAG_TEST (c->flags, CLIENT_FLAG_BELOW | CLIENT_FLAG_FULLSCREEN))
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (clientIsTransientOrModal (c)
            || !FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STICK)
            || FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            insensitive |= MENU_OP_WORKSPACES;
        }
        g_signal_handler_disconnect (GTK_OBJECT (getDefaultGtkWidget ()),
            button_handler_id);
        g_signal_connect (GTK_OBJECT (getDefaultGtkWidget ()),
        "button_press_event", GTK_SIGNAL_FUNC (show_popup_cb),
        (gpointer) NULL);
        removeTmpEventWin (menu_event_window);
        menu_event_window = None;
    /*
       Since all button press/release events are catched by the windows frames, there is some
Olivier Fourdan's avatar
Olivier Fourdan committed
       side effect with GTK menu. When a menu is opened, any click on the window frame is not
       detected as a click outside the menu, and the menu doesn't close.
       To avoid this (painless but annoying) behaviour, we just setup a no event window that
       "hides" the events to regular windows.
       That might look tricky, but it's very efficient and save plenty of lines of complicated
Olivier Fourdan's avatar
Olivier Fourdan committed
       code.
       Don't forget to delete that window once the menu is closed, though, or we'll get in
Olivier Fourdan's avatar
Olivier Fourdan committed
       trouble.
     */
    menu_event_window = setTmpEventWin (0, 0, 
                                        MyDisplayFullWidth (dpy, screen),
                                        MyDisplayFullHeight (dpy, screen), 
                                        NoEventMask);

    menu = menu_default (ops, insensitive, menu_callback, c->win_workspace,
                         params.workspace_count, params.workspace_names,
                         params.workspace_names_length, c);

    if (!menu_popup (menu, x, y, ev->button, ev->time))
    {
        TRACE ("Cannot open menu");
        gdk_beep ();
        c->button_pressed[MENU_BUTTON] = FALSE;
        frameDraw (c, FALSE, FALSE);
        removeTmpEventWin (menu_event_window);
        menu_event_window = None;
        menu_free (menu);
static gboolean
set_reload (void)
        ("setting reload flag so all prefs will be reread at next event loop");
    return (TRUE);
}

static gboolean
dbl_click_time (void)
{
    GValue tmp_val = { 0, };
    TRACE ("setting dbl_click_time");
    g_value_init (&tmp_val, G_TYPE_INT);
    if (gdk_setting_get ("gtk-double-click-time", &tmp_val))
        params.dbl_click_time = abs (g_value_get_int (&tmp_val));
static gboolean
client_event_cb (GtkWidget * widget, GdkEventClient * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering client_event_cb");
        atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE);
    if (ev->message_type == atom_rcfiles)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    GtkSettings *settings;
        g_signal_connect (GTK_OBJECT (getDefaultGtkWidget ()),
        "button_press_event", GTK_SIGNAL_FUNC (show_popup_cb),
        (gpointer) NULL);
    g_signal_connect (GTK_OBJECT (getDefaultGtkWidget ()), "client_event",
        GTK_SIGNAL_FUNC (client_event_cb), (gpointer) NULL);

    settings = gtk_settings_get_default ();
    if (settings)
    {
        g_signal_connect (settings, "notify::gtk-theme-name",
            G_CALLBACK (set_reload), NULL);
        g_signal_connect (settings, "notify::gtk-font-name",
            G_CALLBACK (set_reload), NULL);