mirror of
https://git.yoctoproject.org/libmatchboxwm2
synced 2025-12-01 04:01:22 +08:00
* matchbox/comp-mgr/mb-wm-comp-mgr-clutter.c: * matchbox/comp-mgr/mb-wm-comp-mgr-clutter.h: * matchbox/comp-mgr/mb-wm-comp-mgr.c: * matchbox/comp-mgr/mb-wm-comp-mgr.h: * matchbox/core/mb-wm-client.c: * matchbox/core/mb-wm-types.h: * matchbox/theme-engines/mb-wm-theme-xml.c: * matchbox/theme-engines/mb-wm-theme-xml.h: * matchbox/theme-engines/mb-wm-theme.c: * matchbox/theme-engines/mb-wm-theme.h: Simplified effect framework (effect are no longer themeable).
1095 lines
25 KiB
C
1095 lines
25 KiB
C
/*
|
|
* Matchbox Window Manager II - A lightweight window manager not for the
|
|
* desktop.
|
|
*
|
|
* Authored By Matthew Allum <mallum@o-hand.com>
|
|
*
|
|
* Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include "mb-wm.h"
|
|
#include "mb-wm-theme.h"
|
|
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
|
|
#if ENABLE_COMPOSITE
|
|
#include <X11/extensions/Xrender.h>
|
|
#endif
|
|
|
|
struct MBWindowManagerClientPriv
|
|
{
|
|
Bool realized;
|
|
Bool mapped;
|
|
Bool iconizing;
|
|
Bool hiding_from_desktop;
|
|
MBWMSyncType sync_state;
|
|
};
|
|
|
|
static void
|
|
mb_wm_client_destroy (MBWMObject *obj)
|
|
{
|
|
MBWindowManagerClient * client = MB_WM_CLIENT(obj);
|
|
MBWindowManagerClient * c;
|
|
MBWindowManager * wm = client->wmref;
|
|
MBWMList * l = client->decor;
|
|
|
|
if (client->sig_theme_change_id)
|
|
mb_wm_object_signal_disconnect (MB_WM_OBJECT (wm),
|
|
client->sig_theme_change_id);
|
|
client->sig_theme_change_id = 0;
|
|
|
|
if (client->sig_prop_change_id)
|
|
mb_wm_object_signal_disconnect (MB_WM_OBJECT (client->window),
|
|
client->sig_prop_change_id);
|
|
|
|
client->sig_prop_change_id = 0;
|
|
|
|
if (client->ping_cb_id)
|
|
mb_wm_main_context_timeout_handler_remove (wm->main_ctx,
|
|
client->ping_cb_id);
|
|
|
|
#if ENABLE_COMPOSITE
|
|
if (mb_wm_compositing_enabled (wm))
|
|
{
|
|
mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client);
|
|
}
|
|
#endif
|
|
|
|
mb_wm_object_unref (MB_WM_OBJECT (client->window));
|
|
|
|
while (l)
|
|
{
|
|
mb_wm_object_unref (l->data);
|
|
l = l->next;
|
|
}
|
|
|
|
if (client->transient_for)
|
|
mb_wm_client_remove_transient (client->transient_for, client);
|
|
|
|
/* If we have transient windows, we need to make sure they are unmapped; for
|
|
* application dialogs this will happen automatically, but not for external
|
|
* transients, such as input windows.
|
|
*
|
|
* We also have to make sure that the transients no longer refer to this
|
|
* client, which is about the be destroyed.
|
|
*/
|
|
l = client->transients;
|
|
while (l)
|
|
{
|
|
MBWindowManagerClient * c = l->data;
|
|
MBWMList * l2 = l;
|
|
|
|
c->transient_for = NULL;
|
|
XUnmapWindow (wm->xdpy, c->window->xwindow);
|
|
|
|
l = l->next;
|
|
|
|
free (l2);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
mb_wm_client_on_property_change (MBWMClientWindow *window,
|
|
int property,
|
|
void *userdata);
|
|
|
|
static Bool
|
|
mb_wm_client_on_theme_change (MBWindowManager * wm, int signal,
|
|
MBWindowManagerClient * client)
|
|
{
|
|
mb_wm_client_theme_change (client);
|
|
return False;
|
|
}
|
|
|
|
|
|
static int
|
|
mb_wm_client_init (MBWMObject *obj, va_list vap)
|
|
{
|
|
MBWindowManagerClient *client;
|
|
MBWindowManager *wm = NULL;
|
|
MBWMClientWindow *win = NULL;
|
|
MBWMObjectProp prop;
|
|
int status;
|
|
|
|
prop = va_arg(vap, MBWMObjectProp);
|
|
while (prop)
|
|
{
|
|
switch (prop)
|
|
{
|
|
case MBWMObjectPropWm:
|
|
wm = va_arg(vap, MBWindowManager *);
|
|
break;
|
|
case MBWMObjectPropClientWindow:
|
|
win = va_arg(vap, MBWMClientWindow *);
|
|
break;
|
|
default:
|
|
MBWMO_PROP_EAT (vap, prop);
|
|
}
|
|
|
|
prop = va_arg(vap, MBWMObjectProp);
|
|
}
|
|
|
|
MBWM_MARK();
|
|
|
|
client = MB_WM_CLIENT(obj);
|
|
client->priv = mb_wm_util_malloc0(sizeof(MBWindowManagerClientPriv));
|
|
|
|
client->window = win;
|
|
client->wmref = wm;
|
|
client->ping_timeout = 1000;
|
|
|
|
if (wm->theme)
|
|
{
|
|
client->layout_hints =
|
|
mb_wm_theme_get_client_layout_hints (wm->theme, client);
|
|
}
|
|
|
|
/* sync with client window */
|
|
mb_wm_client_on_property_change (win, MBWM_WINDOW_PROP_ALL, client);
|
|
|
|
/* Handle underlying property changes */
|
|
client->sig_prop_change_id =
|
|
mb_wm_object_signal_connect (MB_WM_OBJECT (win),
|
|
MBWM_WINDOW_PROP_ALL,
|
|
(MBWMObjectCallbackFunc)mb_wm_client_on_property_change,
|
|
client);
|
|
|
|
client->sig_theme_change_id =
|
|
mb_wm_object_signal_connect (MB_WM_OBJECT (wm),
|
|
MBWindowManagerSignalThemeChange,
|
|
(MBWMObjectCallbackFunc)mb_wm_client_on_theme_change,
|
|
client);
|
|
|
|
status = XGrabButton(wm->xdpy, Button1, 0, win->xwindow, True,
|
|
ButtonPressMask,
|
|
GrabModeSync, GrabModeSync, None, None);
|
|
|
|
MBWM_NOTE (CLIENT, "XGrabButton() returned status %d for client window %x",
|
|
status,
|
|
win->xwindow);
|
|
|
|
#if ENABLE_COMPOSITE
|
|
{
|
|
XRenderPictFormat *format;
|
|
|
|
format = XRenderFindVisualFormat (wm->xdpy, win->visual);
|
|
|
|
if (format && format->type == PictTypeDirect &&
|
|
format->direct.alphaMask)
|
|
{
|
|
client->is_argb32 = True;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
mb_wm_client_class_type ()
|
|
{
|
|
static int type = 0;
|
|
|
|
if (UNLIKELY(type == 0))
|
|
{
|
|
static MBWMObjectClassInfo info = {
|
|
sizeof (MBWindowManagerClientClass),
|
|
sizeof (MBWindowManagerClient),
|
|
mb_wm_client_init,
|
|
mb_wm_client_destroy,
|
|
NULL
|
|
};
|
|
|
|
type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_fullscreen_mark_dirty (MBWindowManagerClient *client)
|
|
{
|
|
/* fullscreen implies geometry and visibility sync */
|
|
mb_wm_display_sync_queue (client->wmref,
|
|
MBWMSyncFullscreen |
|
|
MBWMSyncVisibility | MBWMSyncGeometry);
|
|
|
|
client->priv->sync_state |= (MBWMSyncFullscreen |
|
|
MBWMSyncGeometry |
|
|
MBWMSyncVisibility);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_stacking_mark_dirty (MBWindowManagerClient *client)
|
|
{
|
|
mb_wm_display_sync_queue (client->wmref, MBWMSyncStacking);
|
|
client->priv->sync_state |= MBWMSyncStacking;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_geometry_mark_dirty (MBWindowManagerClient *client)
|
|
{
|
|
mb_wm_display_sync_queue (client->wmref, MBWMSyncGeometry);
|
|
|
|
client->priv->sync_state |= MBWMSyncGeometry;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_visibility_mark_dirty (MBWindowManagerClient *client)
|
|
{
|
|
mb_wm_display_sync_queue (client->wmref, MBWMSyncVisibility);
|
|
|
|
client->priv->sync_state |= MBWMSyncVisibility;
|
|
|
|
MBWM_DBG(" sync state: %i", client->priv->sync_state);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_synthetic_config_event_queue (MBWindowManagerClient *client)
|
|
{
|
|
mb_wm_display_sync_queue (client->wmref, MBWMSyncSyntheticConfigEv);
|
|
|
|
client->priv->sync_state |= MBWMSyncSyntheticConfigEv;
|
|
|
|
MBWM_DBG(" sync state: %i", client->priv->sync_state);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_synthetic_config_event (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncSyntheticConfigEv);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_decor_mark_dirty (MBWindowManagerClient *client)
|
|
{
|
|
mb_wm_display_sync_queue (client->wmref, MBWMSyncDecor);
|
|
|
|
client->priv->sync_state |= MBWMSyncDecor;
|
|
|
|
MBWM_DBG(" sync state: %i", client->priv->sync_state);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_fullscreen_sync (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncFullscreen);
|
|
}
|
|
|
|
static Bool
|
|
mb_wm_client_on_property_change (MBWMClientWindow *window,
|
|
int property,
|
|
void *userdata)
|
|
{
|
|
MBWindowManagerClient * client = MB_WM_CLIENT (userdata);
|
|
|
|
if (property & MBWM_WINDOW_PROP_NAME)
|
|
{
|
|
MBWMList * l = client->decor;
|
|
while (l)
|
|
{
|
|
MBWMDecor * decor = l->data;
|
|
|
|
if (mb_wm_decor_get_type (decor) == MBWMDecorTypeNorth)
|
|
{
|
|
mb_wm_decor_mark_title_dirty (decor);
|
|
break;
|
|
}
|
|
|
|
l = l->next;
|
|
}
|
|
}
|
|
|
|
if (property & MBWM_WINDOW_PROP_GEOMETRY)
|
|
mb_wm_client_geometry_mark_dirty (client);
|
|
|
|
#if ENABLE_COMPOSITE
|
|
if ((property & MBWM_WINDOW_PROP_CM_TRANSLUCENCY) &&
|
|
client->cm_client && mb_wm_comp_mgr_enabled (client->wmref->comp_mgr))
|
|
{
|
|
mb_wm_comp_mgr_client_repair (client->cm_client);
|
|
}
|
|
#endif
|
|
|
|
return False;
|
|
}
|
|
|
|
MBWindowManagerClient* /* FIXME: rename to mb_wm_client_base/class_new ? */
|
|
mb_wm_client_new (MBWindowManager *wm, MBWMClientWindow *win)
|
|
{
|
|
MBWindowManagerClient *client = NULL;
|
|
|
|
client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT,
|
|
MBWMObjectPropWm, wm,
|
|
MBWMObjectPropClientWindow, win,
|
|
NULL));
|
|
|
|
return client;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_realize (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
if (client->priv->realized)
|
|
return;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->realize)
|
|
klass->realize(client);
|
|
|
|
client->priv->realized = True;
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_realized (MBWindowManagerClient *client)
|
|
{
|
|
return client->priv->realized;
|
|
}
|
|
|
|
|
|
/* ## Stacking ## */
|
|
|
|
|
|
void
|
|
mb_wm_client_stack (MBWindowManagerClient *client,
|
|
int flags)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->stack)
|
|
{
|
|
klass->stack(client, flags);
|
|
|
|
/* Schedule stack sync, but not if the client is of override type */
|
|
if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeOverride)
|
|
mb_wm_client_stacking_mark_dirty (client);
|
|
}
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_stack_sync (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncStacking);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_show (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->show)
|
|
klass->show (client);
|
|
|
|
client->priv->mapped = True;
|
|
|
|
/* Make sure any Hidden state flag is cleared */
|
|
mb_wm_client_set_state (client,
|
|
MBWM_ATOM_NET_WM_STATE_HIDDEN,
|
|
MBWMClientWindowStateChangeRemove);
|
|
|
|
mb_wm_client_visibility_mark_dirty (client);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_hide (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->hide)
|
|
{
|
|
klass->hide (client);
|
|
|
|
client->priv->mapped = False;
|
|
|
|
mb_wm_unfocus_client (client->wmref, client);
|
|
mb_wm_client_visibility_mark_dirty (client);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The focus processing is split into two stages, client and WM
|
|
*
|
|
* The client stage is handled by this function, with the return value
|
|
* of True indicating that the focus has changed.
|
|
*
|
|
* NB: This function should be considered protected and only called by the
|
|
* MBWindowManager object code.
|
|
*/
|
|
Bool
|
|
mb_wm_client_focus (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
Bool ret = False;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->focus)
|
|
ret = klass->focus(client);
|
|
|
|
if (ret)
|
|
{
|
|
/*
|
|
* If this client is transient, store it with the parent; if it is not
|
|
* transient, reset the last transient field
|
|
*/
|
|
if (client->transient_for)
|
|
client->transient_for->last_focused_transient = client;
|
|
else
|
|
client->last_focused_transient = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_want_focus (MBWindowManagerClient *client)
|
|
{
|
|
return (client->window->want_key_input != False);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_visibility_sync (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncVisibility);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_geometry_sync (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncGeometry);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_decor_sync (MBWindowManagerClient *client)
|
|
{
|
|
return (client->priv->sync_state & MBWMSyncDecor);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_needs_sync (MBWindowManagerClient *client)
|
|
{
|
|
MBWM_DBG("sync_state: %i", client->priv->sync_state);
|
|
|
|
return client->priv->sync_state;
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_mapped (MBWindowManagerClient *client)
|
|
{
|
|
return client->priv->mapped;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_display_sync (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->sync)
|
|
klass->sync (client);
|
|
|
|
client->priv->sync_state = 0;
|
|
}
|
|
|
|
|
|
Bool
|
|
mb_wm_client_request_geometry (MBWindowManagerClient *client,
|
|
MBGeometry *new_geometry,
|
|
MBWMClientReqGeomType flags)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->geometry)
|
|
return klass->geometry(client, new_geometry, flags);
|
|
|
|
return False;
|
|
}
|
|
|
|
MBWMClientLayoutHints
|
|
mb_wm_client_get_layout_hints (MBWindowManagerClient *client)
|
|
{
|
|
if ((client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen))
|
|
{
|
|
if (client->layout_hints & LayoutPrefVisible)
|
|
return (LayoutPrefFullscreen | LayoutPrefVisible);
|
|
else
|
|
return LayoutPrefFullscreen;
|
|
}
|
|
|
|
return client->layout_hints;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_set_layout_hints (MBWindowManagerClient *client,
|
|
MBWMClientLayoutHints hints)
|
|
{
|
|
client->layout_hints = hints;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_set_layout_hint (MBWindowManagerClient *client,
|
|
MBWMClientLayoutHints hint,
|
|
Bool state)
|
|
{
|
|
if (state)
|
|
client->layout_hints |= hint;
|
|
else
|
|
client->layout_hints &= ~hint;
|
|
}
|
|
|
|
void /* needs to be boolean, client may not have any coverage */
|
|
mb_wm_client_get_coverage (MBWindowManagerClient *client,
|
|
MBGeometry *coverage)
|
|
{
|
|
MBGeometry *geometry;
|
|
|
|
if (!client->xwin_frame)
|
|
geometry = &client->window->geometry;
|
|
else
|
|
geometry = &client->frame_geometry;
|
|
|
|
coverage->x = geometry->x;
|
|
coverage->y = geometry->y;
|
|
coverage->width = geometry->width;
|
|
coverage->height = geometry->height;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_add_transient (MBWindowManagerClient *client,
|
|
MBWindowManagerClient *transient)
|
|
{
|
|
MBWMList *l;
|
|
|
|
if (transient == NULL || client == NULL)
|
|
return;
|
|
|
|
transient->transient_for = client;
|
|
|
|
/*
|
|
* Make sure that each transient is only added once (theoretically it should
|
|
* be, but it is very easy for a derived class to call this function without
|
|
* realizing the parent has dones so).
|
|
*/
|
|
l = client->transients;
|
|
while (l)
|
|
{
|
|
if (l->data == transient)
|
|
return;
|
|
|
|
l = l->next;
|
|
}
|
|
|
|
client->transients = mb_wm_util_list_append(client->transients, transient);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_remove_transient (MBWindowManagerClient *client,
|
|
MBWindowManagerClient *transient)
|
|
{
|
|
if (!transient || !client || !client->transients)
|
|
return;
|
|
|
|
transient->transient_for = NULL;
|
|
|
|
client->transients = mb_wm_util_list_remove(client->transients, transient);
|
|
|
|
if (client->last_focused_transient == transient)
|
|
client->last_focused_transient = transient->next_focused_client;
|
|
}
|
|
|
|
MBWMList*
|
|
mb_wm_client_get_transients (MBWindowManagerClient *client)
|
|
{
|
|
MBWMList *trans = NULL;
|
|
MBWMList *l = client->transients;
|
|
Window xgroup = client->window->xwin_group;
|
|
MBWindowManagerClient *c;
|
|
MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
|
|
|
|
while (l)
|
|
{
|
|
trans = mb_wm_util_list_prepend (trans, l->data);
|
|
l = l->next;
|
|
}
|
|
|
|
/* If this is an application or desktop that are part of an group,
|
|
* we add any other transients that are part of the group to the list.
|
|
*/
|
|
if (xgroup &&
|
|
(c_type == MBWMClientTypeApp || c_type == MBWMClientTypeDesktop))
|
|
{
|
|
mb_wm_stack_enumerate (client->wmref, c)
|
|
if (c != client &&
|
|
c->transient_for && c->window->xwin_group == xgroup)
|
|
{
|
|
MBWindowManagerClient * t = c->transient_for;
|
|
|
|
/* Only add it if it is not directly transiet for our client (in
|
|
* which case it is already in the list
|
|
*
|
|
* Find the bottom level transient
|
|
*/
|
|
while (t && t->transient_for)
|
|
t = t->transient_for;
|
|
|
|
if (!t || (MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeApp ||
|
|
MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeDesktop))
|
|
{
|
|
trans = mb_wm_util_list_prepend (trans, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
return trans;
|
|
}
|
|
|
|
MBWindowManagerClient*
|
|
mb_wm_client_get_transient_for (MBWindowManagerClient *client)
|
|
{
|
|
return client->transient_for;
|
|
}
|
|
|
|
|
|
const char*
|
|
mb_wm_client_get_name (MBWindowManagerClient *client)
|
|
{
|
|
if (!client->window)
|
|
return NULL;
|
|
|
|
return client->window->name;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_deliver_message (MBWindowManagerClient *client,
|
|
Atom delivery_atom,
|
|
unsigned long data0,
|
|
unsigned long data1,
|
|
unsigned long data2,
|
|
unsigned long data3,
|
|
unsigned long data4)
|
|
{
|
|
MBWindowManager *wm = client->wmref;
|
|
Window xwin = client->window->xwindow;
|
|
XEvent ev;
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
ev.xclient.type = ClientMessage;
|
|
ev.xclient.window = xwin;
|
|
ev.xclient.message_type = delivery_atom;
|
|
ev.xclient.format = 32;
|
|
ev.xclient.data.l[0] = data0;
|
|
ev.xclient.data.l[1] = data1;
|
|
ev.xclient.data.l[2] = data2;
|
|
ev.xclient.data.l[3] = data3;
|
|
ev.xclient.data.l[4] = data4;
|
|
|
|
XSendEvent(wm->xdpy, xwin, False, NoEventMask, &ev);
|
|
|
|
XSync(wm->xdpy, False);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_deliver_wm_protocol (MBWindowManagerClient *client,
|
|
Atom protocol)
|
|
{
|
|
MBWindowManager *wm = client->wmref;
|
|
|
|
mb_wm_client_deliver_message (client, wm->atoms[MBWM_ATOM_WM_PROTOCOLS],
|
|
protocol, CurrentTime, 0, 0, 0);
|
|
}
|
|
|
|
static void
|
|
mb_wm_client_deliver_ping_protocol (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManager *wm = client->wmref;
|
|
|
|
mb_wm_client_deliver_message (client,
|
|
wm->atoms[MBWM_ATOM_WM_PROTOCOLS],
|
|
wm->atoms[MBWM_ATOM_NET_WM_PING],
|
|
CurrentTime,
|
|
client->window->xwindow,
|
|
0, 0);
|
|
}
|
|
|
|
static Bool
|
|
mb_wm_client_ping_timeout_cb (void * userdata)
|
|
{
|
|
MBWindowManagerClient * client = userdata;
|
|
|
|
mb_wm_client_shutdown (client);
|
|
return False;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_ping_start (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManager * wm = client->wmref;
|
|
MBWMMainContext * ctx = wm->main_ctx;
|
|
|
|
if (client->ping_cb_id)
|
|
return;
|
|
|
|
client->ping_cb_id =
|
|
mb_wm_main_context_timeout_handler_add (ctx, client->ping_timeout,
|
|
mb_wm_client_ping_timeout_cb,
|
|
client);
|
|
|
|
mb_wm_client_deliver_ping_protocol (client);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_ping_stop (MBWindowManagerClient *client)
|
|
{
|
|
MBWMMainContext * ctx = client->wmref->main_ctx;
|
|
|
|
if (!client->ping_cb_id)
|
|
return;
|
|
|
|
mb_wm_main_context_timeout_handler_remove (ctx, client->ping_cb_id);
|
|
client->ping_cb_id = 0;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_shutdown (MBWindowManagerClient *client)
|
|
{
|
|
char buf[257];
|
|
int sig = 9;
|
|
MBWindowManager *wm = client->wmref;
|
|
MBWMClientWindow *win = client->window;
|
|
Window xwin = client->window->xwindow;
|
|
const char *machine = win->machine;
|
|
pid_t pid = win->pid;
|
|
|
|
if (!machine || !pid)
|
|
return;
|
|
|
|
if (gethostname (buf, sizeof(buf)-1) == 0)
|
|
{
|
|
if (!strcmp (buf, machine))
|
|
{
|
|
if (kill (pid, sig) >= 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
XKillClient(wm->xdpy, xwin);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_deliver_delete (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManager *wm = client->wmref;
|
|
Window xwin = client->window->xwindow;
|
|
MBWMClientWindowProtos protos = client->window->protos;
|
|
|
|
if ((protos & MBWMClientWindowProtosDelete))
|
|
{
|
|
mb_wm_client_deliver_wm_protocol (client,
|
|
wm->atoms[MBWM_ATOM_WM_DELETE_WINDOW]);
|
|
|
|
mb_wm_client_ping_start (client);
|
|
}
|
|
else
|
|
mb_wm_client_shutdown (client);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_set_state (MBWindowManagerClient *client,
|
|
MBWMAtom state,
|
|
MBWMClientWindowStateChange state_op)
|
|
{
|
|
MBWindowManager *wm = client->wmref;
|
|
MBWMClientWindow *win = client->window;
|
|
Bool old_state;
|
|
Bool new_state;
|
|
Bool activate = True;
|
|
MBWMClientWindowEWMHState state_flag;
|
|
|
|
switch (state)
|
|
{
|
|
case MBWM_ATOM_NET_WM_STATE_FULLSCREEN:
|
|
state_flag = MBWMClientWindowEWMHStateFullscreen;
|
|
break;
|
|
case MBWM_ATOM_NET_WM_STATE_ABOVE:
|
|
state_flag = MBWMClientWindowEWMHStateAbove;
|
|
break;
|
|
case MBWM_ATOM_NET_WM_STATE_HIDDEN:
|
|
state_flag = MBWMClientWindowEWMHStateHidden;
|
|
break;
|
|
case MBWM_ATOM_NET_WM_STATE_MODAL:
|
|
case MBWM_ATOM_NET_WM_STATE_STICKY:
|
|
case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT:
|
|
case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ:
|
|
case MBWM_ATOM_NET_WM_STATE_SHADED:
|
|
case MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR:
|
|
case MBWM_ATOM_NET_WM_STATE_SKIP_PAGER:
|
|
case MBWM_ATOM_NET_WM_STATE_BELOW:
|
|
case MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION:
|
|
default:
|
|
return; /* not handled yet */
|
|
}
|
|
|
|
old_state = (win->ewmh_state & state_flag);
|
|
|
|
switch (state_op)
|
|
{
|
|
case MBWMClientWindowStateChangeRemove:
|
|
new_state = False;
|
|
break;
|
|
case MBWMClientWindowStateChangeAdd:
|
|
new_state = True;
|
|
break;
|
|
case MBWMClientWindowStateChangeToggle:
|
|
new_state != old_state;
|
|
break;
|
|
}
|
|
|
|
if (new_state == old_state)
|
|
return;
|
|
|
|
if (new_state)
|
|
{
|
|
win->ewmh_state |= state_flag;
|
|
}
|
|
else
|
|
{
|
|
win->ewmh_state &= ~state_flag;
|
|
}
|
|
|
|
if (state_flag & MBWMClientWindowEWMHStateHidden)
|
|
{
|
|
if (new_state)
|
|
mb_wm_client_hide (client);
|
|
else
|
|
mb_wm_client_show (client);
|
|
|
|
return;
|
|
}
|
|
|
|
if ((state_flag & MBWMClientWindowEWMHStateFullscreen))
|
|
{
|
|
mb_wm_client_fullscreen_mark_dirty (client);
|
|
}
|
|
|
|
/*
|
|
* FIXME -- resize && move, possibly redraw decors when returning from
|
|
* fullscreen
|
|
*/
|
|
if (activate)
|
|
mb_wm_activate_client(wm, client);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_ping_in_progress (MBWindowManagerClient * client)
|
|
{
|
|
return (client->ping_cb_id != 0);
|
|
}
|
|
|
|
void
|
|
mb_wm_client_theme_change (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->theme_change)
|
|
klass->theme_change (client);
|
|
}
|
|
|
|
/*
|
|
* Cleanup any transient relationships this client might have
|
|
* (we need to do this when the client window unmaps to ensure correct
|
|
* functioning of the stack).
|
|
*/
|
|
void
|
|
mb_wm_client_detransitise (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
if (!client->transient_for)
|
|
return;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->detransitise)
|
|
klass->detransitise (client);
|
|
|
|
mb_wm_client_remove_transient (client->transient_for, client);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_iconizing (MBWindowManagerClient *client)
|
|
{
|
|
return client->priv->iconizing;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_reset_iconizing (MBWindowManagerClient *client)
|
|
{
|
|
client->priv->iconizing = False;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_iconize (MBWindowManagerClient *client)
|
|
{
|
|
/*
|
|
* Set the iconizing flag and put the window into hidden state
|
|
* This triggers an umap event, at which point the client gets unmanaged
|
|
* by the window manager.
|
|
*/
|
|
#if ENABLE_COMPOSITE
|
|
/*
|
|
* We cannot iconize the client until the effect finished, otherwise it
|
|
* will unmap before the effect takes place, so we do this in the callback.
|
|
*/
|
|
if (mb_wm_compositing_enabled (client->wmref))
|
|
{
|
|
mb_wm_comp_mgr_do_effect (client->wmref->comp_mgr, client,
|
|
MBWMCompMgrEffectEventMinimize);
|
|
}
|
|
#endif
|
|
|
|
client->priv->iconizing = True;
|
|
|
|
|
|
mb_wm_client_set_state (client,
|
|
MBWM_ATOM_NET_WM_STATE_HIDDEN,
|
|
MBWMClientWindowStateChangeAdd);
|
|
}
|
|
|
|
int
|
|
mb_wm_client_title_height (MBWindowManagerClient *client)
|
|
{
|
|
MBWMClientWindow * win = client->window;
|
|
MBWindowManager * wm = client->wmref;
|
|
int north;
|
|
|
|
if (!wm->theme ||
|
|
mb_wm_client_window_is_state_set (win,
|
|
MBWMClientWindowEWMHStateFullscreen))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
mb_wm_theme_get_decor_dimensions (wm->theme, client,
|
|
&north, NULL, NULL, NULL);
|
|
|
|
return north;
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_modal (MBWindowManagerClient *client)
|
|
{
|
|
return mb_wm_client_window_is_state_set (client->window,
|
|
MBWMClientWindowEWMHStateModal);
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_owns_xwindow (MBWindowManagerClient *client, Window xwin)
|
|
{
|
|
MBWMList * l;
|
|
|
|
if (client->xwin_frame == xwin || client->window->xwindow == xwin)
|
|
return True;
|
|
|
|
l = client->decor;
|
|
while (l)
|
|
{
|
|
MBWMDecor * d = l->data;
|
|
|
|
if (d->xwin == xwin)
|
|
return True;
|
|
|
|
l = l->next;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
MBWMStackLayerType
|
|
mb_wm_client_get_stacking_layer (MBWindowManagerClient *client)
|
|
{
|
|
MBWindowManagerClientClass *klass;
|
|
|
|
klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
|
|
|
|
if (klass->stacking_layer)
|
|
return klass->stacking_layer (client);
|
|
|
|
return client->stacking_layer;
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_argb32 (MBWindowManagerClient *client)
|
|
{
|
|
return client->is_argb32;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_set_desktop (MBWindowManagerClient * client, int desktop)
|
|
{
|
|
client->desktop = desktop;
|
|
}
|
|
|
|
int
|
|
mb_wm_client_get_desktop (MBWindowManagerClient * client)
|
|
{
|
|
return client->desktop;
|
|
}
|
|
|
|
void
|
|
mb_wm_client_desktop_change (MBWindowManagerClient * client, int desktop)
|
|
{
|
|
if (client->desktop < 0)
|
|
return;
|
|
|
|
if (client->desktop == desktop)
|
|
{
|
|
client->priv->hiding_from_desktop = False;
|
|
|
|
mb_wm_client_set_state (client,
|
|
MBWM_ATOM_NET_WM_STATE_HIDDEN,
|
|
MBWMClientWindowStateChangeRemove);
|
|
}
|
|
else
|
|
{
|
|
client->priv->hiding_from_desktop = True;
|
|
|
|
mb_wm_client_set_state (client,
|
|
MBWM_ATOM_NET_WM_STATE_HIDDEN,
|
|
MBWMClientWindowStateChangeAdd);
|
|
}
|
|
}
|
|
|
|
Bool
|
|
mb_wm_client_is_hiding_from_desktop (MBWindowManagerClient * client)
|
|
{
|
|
return client->priv->hiding_from_desktop;
|
|
}
|