mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 16:40:41 -05:00
...
This commit is contained in:
parent
e47c4d16a2
commit
ce7c53bf1a
@ -62,6 +62,9 @@ PKG_CHECK_MODULES(METACITY, $PANGO_PACKAGES)
|
||||
# Check for shaped window extension
|
||||
AC_CHECK_LIB(Xext, XShapeCombineMask, AC_DEFINE(HAVE_SHAPE_EXT),,$METACITY_LIBS)
|
||||
|
||||
HOST_ALIAS=$host_alias
|
||||
AC_SUBST(HOST_ALIAS)
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
intl/Makefile
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
SUBDIRS=uislave
|
||||
|
||||
INCLUDES=@METACITY_CFLAGS@
|
||||
INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\"
|
||||
|
||||
metacity_SOURCES= \
|
||||
api.c \
|
||||
|
183
src/display.c
183
src/display.c
@ -24,14 +24,18 @@
|
||||
#include "main.h"
|
||||
#include "screen.h"
|
||||
#include "window.h"
|
||||
#include "frame.h"
|
||||
|
||||
static GSList *all_displays = NULL;
|
||||
static void meta_spew_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
static void event_queue_callback (MetaEventQueue *queue,
|
||||
XEvent *event,
|
||||
gpointer data);
|
||||
static Window event_get_modified_window (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
|
||||
static void meta_spew_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
static void event_queue_callback (MetaEventQueue *queue,
|
||||
XEvent *event,
|
||||
gpointer data);
|
||||
|
||||
|
||||
static gint
|
||||
@ -63,7 +67,7 @@ meta_display_open (const char *name)
|
||||
GSList *screens;
|
||||
GSList *tmp;
|
||||
int i;
|
||||
char *atom_names[] = { "_NET_WM_NAME" };
|
||||
char *atom_names[] = { "_NET_WM_NAME", "WM_PROTOCOLS", "WM_TAKE_FOCUS", "WM_DELETE_WINDOW" };
|
||||
Atom atoms[G_N_ELEMENTS(atom_names)];
|
||||
|
||||
meta_verbose ("Opening display '%s'\n", XDisplayName (name));
|
||||
@ -81,7 +85,11 @@ meta_display_open (const char *name)
|
||||
XSynchronize (xdisplay, True);
|
||||
|
||||
display = g_new (MetaDisplay, 1);
|
||||
|
||||
|
||||
/* here we use XDisplayName which is what the user
|
||||
* probably put in, vs. DisplayString(display) which is
|
||||
* canonicalized by XOpenDisplay()
|
||||
*/
|
||||
display->name = g_strdup (XDisplayName (name));
|
||||
display->xdisplay = xdisplay;
|
||||
display->error_traps = NULL;
|
||||
@ -277,26 +285,26 @@ event_queue_callback (MetaEventQueue *queue,
|
||||
{
|
||||
MetaWindow *window;
|
||||
MetaDisplay *display;
|
||||
gboolean is_root;
|
||||
Window modified;
|
||||
|
||||
display = data;
|
||||
|
||||
if (dump_events)
|
||||
meta_spew_event (display, event);
|
||||
|
||||
is_root = meta_display_screen_for_root (display, event->xany.window) != NULL;
|
||||
window = NULL;
|
||||
modified = event_get_modified_window (display, event);
|
||||
|
||||
if (modified != None)
|
||||
window = meta_display_lookup_x_window (display, modified);
|
||||
else
|
||||
window = NULL;
|
||||
|
||||
if (!is_root)
|
||||
if (window &&
|
||||
window->frame &&
|
||||
modified == window->frame->xwindow)
|
||||
{
|
||||
if (window == NULL)
|
||||
window = meta_display_lookup_x_window (display, event->xany.window);
|
||||
|
||||
if (window != NULL)
|
||||
{
|
||||
if (meta_window_event (window, event))
|
||||
return;
|
||||
}
|
||||
meta_frame_event (window->frame, event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->type)
|
||||
@ -332,28 +340,59 @@ event_queue_callback (MetaEventQueue *queue,
|
||||
case CreateNotify:
|
||||
break;
|
||||
case DestroyNotify:
|
||||
if (window)
|
||||
meta_window_free (window); /* Unmanage destroyed window */
|
||||
break;
|
||||
case UnmapNotify:
|
||||
if (window)
|
||||
meta_window_free (window); /* Unmanage withdrawn window */
|
||||
break;
|
||||
case MapNotify:
|
||||
break;
|
||||
case MapRequest:
|
||||
if (is_root && !event->xmap.override_redirect)
|
||||
{
|
||||
/* Window requested mapping. Manage it if we haven't. Note that
|
||||
* meta_window_new() can return NULL
|
||||
*/
|
||||
window = meta_display_lookup_x_window (display,
|
||||
event->xmaprequest.window);
|
||||
if (window == NULL)
|
||||
window = meta_window_new (display, event->xmaprequest.window);
|
||||
}
|
||||
if (window == NULL)
|
||||
window = meta_window_new (display, event->xmaprequest.window);
|
||||
break;
|
||||
case ReparentNotify:
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
if (event->xconfigure.override_redirect)
|
||||
{
|
||||
/* Unmanage it, override_redirect was toggled on?
|
||||
* Can this happen?
|
||||
*/
|
||||
meta_window_free (window);
|
||||
}
|
||||
break;
|
||||
case ConfigureRequest:
|
||||
/* This comment and code is found in both twm and fvwm */
|
||||
/*
|
||||
* According to the July 27, 1988 ICCCM draft, we should ignore size and
|
||||
* position fields in the WM_NORMAL_HINTS property when we map a window.
|
||||
* Instead, we'll read the current geometry. Therefore, we should respond
|
||||
* to configuration requests for windows which have never been mapped.
|
||||
*/
|
||||
if (window == NULL)
|
||||
{
|
||||
unsigned int xwcm;
|
||||
XWindowChanges xwc;
|
||||
|
||||
xwcm = event->xconfigurerequest.value_mask &
|
||||
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
|
||||
|
||||
xwc.x = event->xconfigurerequest.x;
|
||||
xwc.y = event->xconfigurerequest.y;
|
||||
xwc.width = event->xconfigurerequest.width;
|
||||
xwc.height = event->xconfigurerequest.height;
|
||||
xwc.border_width = event->xconfigurerequest.border_width;
|
||||
|
||||
XConfigureWindow (display->xdisplay, event->xconfigurerequest.window,
|
||||
xwcm, &xwc);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_window_configure_request (window, event);
|
||||
}
|
||||
break;
|
||||
case GravityNotify:
|
||||
break;
|
||||
@ -364,6 +403,8 @@ event_queue_callback (MetaEventQueue *queue,
|
||||
case CirculateRequest:
|
||||
break;
|
||||
case PropertyNotify:
|
||||
if (window)
|
||||
meta_window_property_notify (window, event);
|
||||
break;
|
||||
case SelectionClear:
|
||||
break;
|
||||
@ -379,9 +420,83 @@ event_queue_callback (MetaEventQueue *queue,
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the window this has to do with, if any, rather
|
||||
* than the frame or root window that was selecting
|
||||
* for substructure
|
||||
*/
|
||||
static Window
|
||||
event_get_modified_window (MetaDisplay *display,
|
||||
XEvent *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
case MotionNotify:
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
case FocusIn:
|
||||
case FocusOut:
|
||||
case KeymapNotify:
|
||||
case Expose:
|
||||
case GraphicsExpose:
|
||||
case NoExpose:
|
||||
case VisibilityNotify:
|
||||
case ResizeRequest:
|
||||
case PropertyNotify:
|
||||
case SelectionClear:
|
||||
case SelectionRequest:
|
||||
case SelectionNotify:
|
||||
case ColormapNotify:
|
||||
case ClientMessage:
|
||||
return event->xany.window;
|
||||
|
||||
case CreateNotify:
|
||||
return event->xcreatewindow.window;
|
||||
|
||||
case DestroyNotify:
|
||||
return event->xdestroywindow.window;
|
||||
|
||||
case UnmapNotify:
|
||||
return event->xunmap.window;
|
||||
|
||||
case MapNotify:
|
||||
return event->xmap.window;
|
||||
|
||||
case MapRequest:
|
||||
return event->xmaprequest.window;
|
||||
|
||||
case ReparentNotify:
|
||||
return event->xreparent.window;
|
||||
|
||||
case ConfigureNotify:
|
||||
return event->xconfigure.window;
|
||||
|
||||
case ConfigureRequest:
|
||||
return event->xconfigurerequest.window;
|
||||
|
||||
case GravityNotify:
|
||||
return event->xgravity.window;
|
||||
|
||||
case CirculateNotify:
|
||||
return event->xcirculate.window;
|
||||
|
||||
case CirculateRequest:
|
||||
return event->xcirculaterequest.window;
|
||||
|
||||
case MappingNotify:
|
||||
return None;
|
||||
|
||||
default:
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_spew_event (MetaDisplay *display,
|
||||
XEvent *event)
|
||||
@ -465,6 +580,14 @@ meta_spew_event (MetaDisplay *display,
|
||||
break;
|
||||
case ConfigureRequest:
|
||||
name = "ConfigureRequest";
|
||||
extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d y: %d w: %d h: %d border: %d",
|
||||
event->xconfigurerequest.parent,
|
||||
event->xconfigurerequest.window,
|
||||
event->xconfigurerequest.x,
|
||||
event->xconfigurerequest.y,
|
||||
event->xconfigurerequest.width,
|
||||
event->xconfigurerequest.height,
|
||||
event->xconfigurerequest.border_width);
|
||||
break;
|
||||
case GravityNotify:
|
||||
name = "GravityNotify";
|
||||
|
@ -31,6 +31,7 @@ typedef struct _MetaDisplay MetaDisplay;
|
||||
typedef struct _MetaFrame MetaFrame;
|
||||
typedef struct _MetaScreen MetaScreen;
|
||||
typedef struct _MetaWindow MetaWindow;
|
||||
typedef struct _MetaUISlave MetaUISlave;
|
||||
|
||||
struct _MetaDisplay
|
||||
{
|
||||
@ -38,6 +39,9 @@ struct _MetaDisplay
|
||||
Display *xdisplay;
|
||||
|
||||
Atom atom_net_wm_name;
|
||||
Atom atom_wm_protocols;
|
||||
Atom atom_wm_take_focus;
|
||||
Atom atom_wm_delete_window;
|
||||
|
||||
/*< private-ish >*/
|
||||
MetaEventQueue *events;
|
||||
|
372
src/frame.c
372
src/frame.c
@ -37,109 +37,145 @@ meta_frame_init_info (MetaFrame *frame,
|
||||
info->height = frame->rect.height;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_frame_calc_initial_pos (MetaFrame *frame,
|
||||
int child_root_x, int child_root_y)
|
||||
{
|
||||
MetaWindow *window;
|
||||
|
||||
window = frame->window;
|
||||
|
||||
switch (window->size_hints.win_gravity)
|
||||
{
|
||||
case NorthWestGravity:
|
||||
frame->rect.x = child_root_x;
|
||||
frame->rect.y = child_root_y;
|
||||
break;
|
||||
case NorthGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width / 2;
|
||||
frame->rect.y = child_root_y;
|
||||
break;
|
||||
case NorthEastGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width;
|
||||
frame->rect.y = child_root_y;
|
||||
break;
|
||||
case WestGravity:
|
||||
frame->rect.x = child_root_x;
|
||||
frame->rect.y = child_root_y - frame->rect.height / 2;
|
||||
break;
|
||||
case CenterGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width / 2;
|
||||
frame->rect.y = child_root_y - frame->rect.height / 2;
|
||||
break;
|
||||
case EastGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width;
|
||||
frame->rect.y = child_root_y - frame->rect.height / 2;
|
||||
break;
|
||||
case SouthWestGravity:
|
||||
frame->rect.x = child_root_x;
|
||||
frame->rect.y = child_root_y - frame->rect.height;
|
||||
break;
|
||||
case SouthGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width / 2;
|
||||
frame->rect.y = child_root_y - frame->rect.height;
|
||||
break;
|
||||
case SouthEastGravity:
|
||||
frame->rect.x = child_root_x - frame->rect.width;
|
||||
frame->rect.y = child_root_y - frame->rect.height;
|
||||
break;
|
||||
case StaticGravity:
|
||||
default:
|
||||
frame->rect.x = child_root_x - frame->child_x;
|
||||
frame->rect.y = child_root_y - frame->child_y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_frame_calc_geometry (MetaFrame *frame,
|
||||
int child_width, int child_height,
|
||||
MetaFrameGeometry *geomp)
|
||||
{
|
||||
MetaFrameInfo info;
|
||||
MetaFrameGeometry geom;
|
||||
MetaWindow *window;
|
||||
|
||||
/* Remember this is called from the constructor
|
||||
* pre-window-creation.
|
||||
*/
|
||||
|
||||
window = frame->window;
|
||||
|
||||
frame->rect.width = child_width;
|
||||
frame->rect.height = child_height;
|
||||
|
||||
meta_frame_init_info (frame, &info);
|
||||
|
||||
if (!frame->theme_acquired)
|
||||
frame->theme_data = window->screen->engine->acquire_frame (&info);
|
||||
|
||||
geom.left_width = 0;
|
||||
geom.right_width = 0;
|
||||
geom.top_height = 0;
|
||||
geom.bottom_height = 0;
|
||||
geom.background_pixel = BlackPixel (window->display->xdisplay,
|
||||
window->screen->number);
|
||||
|
||||
geom.shape_mask = None;
|
||||
|
||||
window->screen->engine->fill_frame_geometry (&info, &geom,
|
||||
frame->theme_data);
|
||||
|
||||
frame->child_x = geom.left_width;
|
||||
frame->child_y = geom.top_height;
|
||||
|
||||
frame->rect.width = frame->rect.width + geom.left_width + geom.right_width;
|
||||
frame->rect.height = frame->rect.height + geom.top_height + geom.bottom_height;
|
||||
|
||||
*geomp = geom;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_ensure_frame (MetaWindow *window)
|
||||
{
|
||||
MetaFrame *frame;
|
||||
int child_x, child_y;
|
||||
unsigned long background_pixel;
|
||||
XSetWindowAttributes attrs;
|
||||
MetaFrameInfo info;
|
||||
MetaFrameGeometry geom;
|
||||
|
||||
if (window->frame)
|
||||
return;
|
||||
|
||||
/* Need to fix Pango, it grabs the server */
|
||||
g_return_if_fail (window->display->server_grab_count == 0);
|
||||
|
||||
frame = g_new (MetaFrame, 1);
|
||||
|
||||
/* Fill in values that calc_geometry will use */
|
||||
frame->window = window;
|
||||
|
||||
/* Fill these in for the theme engine's benefit */
|
||||
frame->xwindow = None;
|
||||
frame->rect.width = window->rect.width;
|
||||
frame->rect.height = window->rect.height;
|
||||
|
||||
meta_frame_init_info (frame, &info);
|
||||
frame->theme_acquired = FALSE;
|
||||
|
||||
geom.left_width = 0;
|
||||
geom.right_width = 0;
|
||||
geom.top_height = 0;
|
||||
geom.bottom_height = 0;
|
||||
geom.background_pixel = BlackPixel (frame->window->display->xdisplay,
|
||||
frame->window->screen->number);
|
||||
/* This fills in frame->rect as well. */
|
||||
meta_frame_calc_geometry (frame,
|
||||
window->rect.width,
|
||||
window->rect.height,
|
||||
&geom);
|
||||
|
||||
geom.shape_mask = None;
|
||||
|
||||
frame->theme_data = window->screen->engine->acquire_frame (&info);
|
||||
window->screen->engine->fill_frame_geometry (&info, &geom,
|
||||
frame->theme_data);
|
||||
|
||||
child_x = geom.left_width;
|
||||
child_y = geom.top_height;
|
||||
|
||||
frame->rect.width = window->rect.width + geom.left_width + geom.right_width;
|
||||
frame->rect.height = window->rect.height + geom.top_height + geom.bottom_height;
|
||||
|
||||
background_pixel = geom.background_pixel;
|
||||
|
||||
switch (window->size_hints.win_gravity)
|
||||
{
|
||||
case NorthWestGravity:
|
||||
frame->rect.x = window->rect.x;
|
||||
frame->rect.y = window->rect.y;
|
||||
break;
|
||||
case NorthGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width / 2;
|
||||
frame->rect.y = window->rect.y;
|
||||
break;
|
||||
case NorthEastGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width;
|
||||
frame->rect.y = window->rect.y;
|
||||
break;
|
||||
case WestGravity:
|
||||
frame->rect.x = window->rect.x;
|
||||
frame->rect.y = window->rect.y - frame->rect.height / 2;
|
||||
break;
|
||||
case CenterGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width / 2;
|
||||
frame->rect.y = window->rect.y - frame->rect.height / 2;
|
||||
break;
|
||||
case EastGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width;
|
||||
frame->rect.y = window->rect.y - frame->rect.height / 2;
|
||||
break;
|
||||
case SouthWestGravity:
|
||||
frame->rect.x = window->rect.x;
|
||||
frame->rect.y = window->rect.y - frame->rect.height;
|
||||
break;
|
||||
case SouthGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width / 2;
|
||||
frame->rect.y = window->rect.y - frame->rect.height;
|
||||
break;
|
||||
case SouthEastGravity:
|
||||
frame->rect.x = window->rect.x - frame->rect.width;
|
||||
frame->rect.y = window->rect.y - frame->rect.height;
|
||||
break;
|
||||
case StaticGravity:
|
||||
default:
|
||||
frame->rect.x = window->rect.x - child_x;
|
||||
frame->rect.y = window->rect.y - child_y;
|
||||
break;
|
||||
}
|
||||
|
||||
meta_verbose ("Creating frame %d,%d %dx%d around window 0x%lx %d,%d %dx%d with child position inside frame %d,%d and gravity %d\n",
|
||||
meta_frame_calc_initial_pos (frame, window->rect.x, window->rect.y);
|
||||
|
||||
meta_verbose ("Will create frame %d,%d %dx%d around window %s %d,%d %dx%d with child position inside frame %d,%d and gravity %d\n",
|
||||
frame->rect.x, frame->rect.y,
|
||||
frame->rect.width, frame->rect.height,
|
||||
window->xwindow,
|
||||
window->desc,
|
||||
window->rect.x, window->rect.y,
|
||||
window->rect.width, window->rect.height,
|
||||
child_x, child_y,
|
||||
frame->child_x, frame->child_y,
|
||||
window->size_hints.win_gravity);
|
||||
|
||||
attrs.background_pixel = background_pixel;
|
||||
|
||||
attrs.background_pixel = geom.background_pixel;
|
||||
attrs.event_mask =
|
||||
StructureNotifyMask | ExposureMask |
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
|
||||
ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask |
|
||||
PointerMotionMask | PointerMotionHintMask;
|
||||
|
||||
frame->xwindow = XCreateWindow (window->display->xdisplay,
|
||||
@ -177,10 +213,14 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
frame->xwindow,
|
||||
child_x,
|
||||
child_y);
|
||||
frame->child_x,
|
||||
frame->child_y);
|
||||
meta_error_trap_pop (window->display);
|
||||
|
||||
/* Update window's location */
|
||||
window->rect.x = frame->child_x;
|
||||
window->rect.y = frame->child_y;
|
||||
|
||||
/* stick frame to the window */
|
||||
window->frame = frame;
|
||||
|
||||
@ -246,6 +286,90 @@ meta_frame_move (MetaFrame *frame,
|
||||
root_x, root_y);
|
||||
}
|
||||
|
||||
/* Just a chunk of process_configure_event in window.c,
|
||||
* moved here since it's the part that deals with
|
||||
* the frame.
|
||||
*/
|
||||
void
|
||||
meta_frame_child_configure_request (MetaFrame *frame)
|
||||
{
|
||||
MetaFrameGeometry geom;
|
||||
|
||||
/* This fills in frame->rect as well. */
|
||||
meta_frame_calc_geometry (frame,
|
||||
frame->window->size_hints.width,
|
||||
frame->window->size_hints.height,
|
||||
&geom);
|
||||
|
||||
meta_frame_calc_initial_pos (frame,
|
||||
frame->window->size_hints.x,
|
||||
frame->window->size_hints.y);
|
||||
|
||||
XMoveResizeWindow (frame->window->display->xdisplay,
|
||||
frame->xwindow,
|
||||
frame->rect.x,
|
||||
frame->rect.y,
|
||||
frame->rect.width,
|
||||
frame->rect.height);
|
||||
}
|
||||
|
||||
void
|
||||
meta_frame_recalc_now (MetaFrame *frame)
|
||||
{
|
||||
int old_child_x, old_child_y;
|
||||
MetaFrameGeometry geom;
|
||||
XSetWindowAttributes attrs;
|
||||
|
||||
old_child_x = frame->child_x;
|
||||
old_child_y = frame->child_y;
|
||||
|
||||
/* This fills in frame->rect as well. */
|
||||
meta_frame_calc_geometry (frame,
|
||||
frame->window->rect.width,
|
||||
frame->window->rect.height,
|
||||
&geom);
|
||||
|
||||
/* See if we need to move the frame to keep child in
|
||||
* a constant position
|
||||
*/
|
||||
if (old_child_x != frame->child_x)
|
||||
frame->rect.x += (frame->child_x - old_child_x);
|
||||
if (old_child_y != frame->child_y)
|
||||
frame->rect.y += (frame->child_y - old_child_y);
|
||||
|
||||
XMoveResizeWindow (frame->window->display->xdisplay,
|
||||
frame->xwindow,
|
||||
frame->rect.x,
|
||||
frame->rect.y,
|
||||
frame->rect.width,
|
||||
frame->rect.height);
|
||||
|
||||
attrs.background_pixel = geom.background_pixel;
|
||||
XChangeWindowAttributes (frame->window->display->xdisplay,
|
||||
frame->xwindow,
|
||||
CWBackPixel,
|
||||
&attrs);
|
||||
|
||||
meta_verbose ("Frame of %s recalculated to %d,%d %d x %d child %d,%d\n",
|
||||
frame->window->desc, frame->rect.x, frame->rect.y,
|
||||
frame->rect.width, frame->rect.height,
|
||||
frame->child_x, frame->child_y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_frame_queue_recalc (MetaFrame *frame)
|
||||
{
|
||||
/* FIXME */
|
||||
meta_frame_recalc_now (frame);
|
||||
}
|
||||
|
||||
void
|
||||
meta_frame_queue_draw (MetaFrame *frame)
|
||||
{
|
||||
/* FIXME */
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
frame_query_root_pointer (MetaFrame *frame,
|
||||
int *x, int *y)
|
||||
@ -283,6 +407,37 @@ frame_get_control (MetaFrame *frame,
|
||||
frame->theme_data);
|
||||
}
|
||||
|
||||
static void
|
||||
update_move (MetaFrame *frame)
|
||||
{
|
||||
int x, y;
|
||||
int new_x, new_y;
|
||||
frame_query_root_pointer (frame, &x, &y);
|
||||
|
||||
new_x = frame->rect.x + (x - frame->last_x);
|
||||
new_y = frame->rect.y + (y - frame->last_y);
|
||||
frame->last_x = x;
|
||||
frame->last_y = y;
|
||||
|
||||
meta_frame_move (frame, new_x, new_y);
|
||||
}
|
||||
|
||||
static void
|
||||
update_resize_se (MetaFrame *frame)
|
||||
{
|
||||
int x, y;
|
||||
int new_w, new_h;
|
||||
|
||||
frame_query_root_pointer (frame, &x, &y);
|
||||
|
||||
new_w = frame->window->rect.width + (x - frame->last_x);
|
||||
new_h = frame->window->rect.height + (y - frame->last_y);
|
||||
frame->last_x = x;
|
||||
frame->last_y = y;
|
||||
|
||||
meta_window_resize (frame->window, new_w, new_h);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_frame_event (MetaFrame *frame,
|
||||
XEvent *event)
|
||||
@ -323,15 +478,32 @@ meta_frame_event (MetaFrame *frame,
|
||||
else if (control == META_FRAME_CONTROL_RESIZE_SE &&
|
||||
event->xbutton.button == 1)
|
||||
{
|
||||
/* FIXME begin a resize */
|
||||
meta_verbose ("Resize control clicked on %s\n",
|
||||
frame->window->desc);
|
||||
frame->action = META_FRAME_ACTION_RESIZING_SE;
|
||||
frame->last_x = event->xbutton.x_root;
|
||||
frame->last_y = event->xbutton.y_root;
|
||||
frame->start_button = event->xbutton.button;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ButtonRelease:
|
||||
if (event->xbutton.button == frame->start_button)
|
||||
{
|
||||
switch (frame->action)
|
||||
{
|
||||
case META_FRAME_ACTION_MOVING:
|
||||
update_move (frame);
|
||||
break;
|
||||
|
||||
case META_FRAME_ACTION_RESIZING_SE:
|
||||
update_resize_se (frame);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
frame->action = META_FRAME_ACTION_NONE;
|
||||
}
|
||||
break;
|
||||
@ -339,20 +511,13 @@ meta_frame_event (MetaFrame *frame,
|
||||
switch (frame->action)
|
||||
{
|
||||
case META_FRAME_ACTION_MOVING:
|
||||
{
|
||||
int x, y;
|
||||
int new_x, new_y;
|
||||
frame_query_root_pointer (frame, &x, &y);
|
||||
|
||||
new_x = frame->rect.x + (x - frame->last_x);
|
||||
new_y = frame->rect.y + (y - frame->last_y);
|
||||
frame->last_x = x;
|
||||
frame->last_y = y;
|
||||
|
||||
meta_frame_move (frame, new_x, new_y);
|
||||
}
|
||||
update_move (frame);
|
||||
break;
|
||||
|
||||
case META_FRAME_ACTION_RESIZING_SE:
|
||||
update_resize_se (frame);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -388,11 +553,16 @@ meta_frame_event (MetaFrame *frame,
|
||||
case CreateNotify:
|
||||
break;
|
||||
case DestroyNotify:
|
||||
meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", frame->xwindow);
|
||||
meta_error_trap_push (frame->window->display);
|
||||
meta_window_destroy_frame (frame->window);
|
||||
meta_error_trap_pop (frame->window->display);
|
||||
return TRUE;
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", frame->xwindow);
|
||||
display = frame->window->display;
|
||||
meta_error_trap_push (display);
|
||||
meta_window_destroy_frame (frame->window);
|
||||
meta_error_trap_pop (display);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case UnmapNotify:
|
||||
frame->action = META_FRAME_ACTION_NONE;
|
||||
|
29
src/frame.h
29
src/frame.h
@ -28,7 +28,7 @@ typedef enum
|
||||
{
|
||||
META_FRAME_ACTION_NONE,
|
||||
META_FRAME_ACTION_MOVING,
|
||||
META_FRAME_ACTION_RESIZING
|
||||
META_FRAME_ACTION_RESIZING_SE
|
||||
} MetaFrameAction;
|
||||
|
||||
struct _MetaFrame
|
||||
@ -43,6 +43,8 @@ struct _MetaFrame
|
||||
* frame, not the result of ConfigureNotify
|
||||
*/
|
||||
MetaRectangle rect;
|
||||
int child_x;
|
||||
int child_y;
|
||||
|
||||
gpointer theme_data;
|
||||
|
||||
@ -50,16 +52,27 @@ struct _MetaFrame
|
||||
/* reference point for drags */
|
||||
int last_x, last_y;
|
||||
int start_button;
|
||||
|
||||
guint theme_acquired : 1;
|
||||
};
|
||||
|
||||
void meta_window_ensure_frame (MetaWindow *window);
|
||||
void meta_window_destroy_frame (MetaWindow *window);
|
||||
void meta_window_ensure_frame (MetaWindow *window);
|
||||
void meta_window_destroy_frame (MetaWindow *window);
|
||||
void meta_frame_move (MetaFrame *frame,
|
||||
int root_x,
|
||||
int root_y);
|
||||
void meta_frame_child_configure_request (MetaFrame *frame);
|
||||
void meta_frame_recalc_now (MetaFrame *frame);
|
||||
void meta_frame_queue_recalc (MetaFrame *frame);
|
||||
void meta_frame_queue_draw (MetaFrame *frame);
|
||||
gboolean meta_frame_event (MetaFrame *frame,
|
||||
XEvent *event);
|
||||
|
||||
|
||||
void meta_frame_move (MetaFrame *frame,
|
||||
int root_x,
|
||||
int root_y);
|
||||
|
||||
gboolean meta_frame_event (MetaFrame *frame,
|
||||
XEvent *event);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#! /bin/bash
|
||||
|
||||
Xnest :1 -scrns 2 -geometry 270x270 &
|
||||
sleep 1
|
||||
DISPLAY=:1 unst $1 ./metacity
|
||||
METACITY_UISLAVE_DIR=./uislave DISPLAY=:1 unst libtool --mode=execute gdb ./metacity
|
||||
killall Xnest
|
||||
|
84
src/screen.c
84
src/screen.c
@ -24,11 +24,19 @@
|
||||
#include "errors.h"
|
||||
#include "window.h"
|
||||
#include "colors.h"
|
||||
#include "uislave.h"
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
||||
static void ui_slave_func (MetaUISlave *uislave,
|
||||
MetaMessage *message,
|
||||
gpointer data);
|
||||
static char* get_screen_name (MetaDisplay *display,
|
||||
int number);
|
||||
|
||||
|
||||
MetaScreen*
|
||||
meta_screen_new (MetaDisplay *display,
|
||||
int number)
|
||||
@ -83,14 +91,19 @@ meta_screen_new (MetaDisplay *display,
|
||||
|
||||
screen->display = display;
|
||||
screen->number = number;
|
||||
screen->screen_name = get_screen_name (display, number);
|
||||
screen->xscreen = ScreenOfDisplay (xdisplay, number);
|
||||
screen->xroot = xroot;
|
||||
screen->pango_context = NULL;
|
||||
|
||||
screen->engine = &meta_default_engine;
|
||||
|
||||
meta_verbose ("Added screen %d on display '%s' root 0x%lx\n",
|
||||
screen->number, screen->display->name, screen->xroot);
|
||||
screen->engine = &meta_default_engine;
|
||||
|
||||
screen->uislave = meta_ui_slave_new (screen->screen_name,
|
||||
ui_slave_func,
|
||||
screen);
|
||||
|
||||
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
|
||||
screen->number, screen->screen_name, screen->xroot);
|
||||
|
||||
return screen;
|
||||
}
|
||||
@ -98,8 +111,10 @@ meta_screen_new (MetaDisplay *display,
|
||||
void
|
||||
meta_screen_free (MetaScreen *screen)
|
||||
{
|
||||
meta_ui_slave_free (screen->uislave);
|
||||
if (screen->pango_context)
|
||||
g_object_unref (G_OBJECT (screen->pango_context));
|
||||
g_free (screen->screen_name);
|
||||
g_free (screen);
|
||||
}
|
||||
|
||||
@ -256,3 +271,64 @@ meta_screen_for_x_screen (Screen *xscreen)
|
||||
|
||||
return meta_display_screen_for_x_screen (display, xscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
ui_slave_func (MetaUISlave *uislave,
|
||||
MetaMessage *message,
|
||||
gpointer data)
|
||||
{
|
||||
switch (message->header.message_code)
|
||||
{
|
||||
case MetaMessageCheckCode:
|
||||
meta_verbose ("Received UI slave check message version: %s host alias: %s messages version: %d\n",
|
||||
message->check.metacity_version,
|
||||
message->check.host_alias,
|
||||
message->check.messages_version);
|
||||
|
||||
if (strcmp (message->check.metacity_version, VERSION) != 0 ||
|
||||
strcmp (message->check.host_alias, HOST_ALIAS) != 0 ||
|
||||
message->check.messages_version != META_MESSAGES_VERSION)
|
||||
{
|
||||
meta_warning ("metacity-uislave has the wrong version; must use the one compiled with metacity\n");
|
||||
meta_ui_slave_disable (uislave);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
meta_verbose ("Received unhandled message from UI slave: %d\n",
|
||||
message->header.message_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
get_screen_name (MetaDisplay *display,
|
||||
int number)
|
||||
{
|
||||
char *p;
|
||||
char *dname;
|
||||
char *scr;
|
||||
|
||||
/* DisplayString gives us a sort of canonical display,
|
||||
* vs. the user-entered name from XDisplayName()
|
||||
*/
|
||||
dname = g_strdup (DisplayString (display->xdisplay));
|
||||
|
||||
/* Change display name to specify this screen.
|
||||
*/
|
||||
p = strrchr (dname, ':');
|
||||
if (p)
|
||||
{
|
||||
p = strchr (p, '.');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
scr = g_strdup_printf ("%s.%d", dname, number);
|
||||
|
||||
g_free (dname);
|
||||
|
||||
return scr;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ struct _MetaScreen
|
||||
{
|
||||
MetaDisplay *display;
|
||||
int number;
|
||||
char *screen_name;
|
||||
Screen *xscreen;
|
||||
Window xroot;
|
||||
|
||||
@ -39,7 +40,9 @@ struct _MetaScreen
|
||||
/* we only need one since we only draw to a single visual (that of
|
||||
* root window)
|
||||
*/
|
||||
PangoContext *pango_context;
|
||||
PangoContext *pango_context;
|
||||
|
||||
MetaUISlave *uislave;
|
||||
};
|
||||
|
||||
MetaScreen* meta_screen_new (MetaDisplay *display,
|
||||
|
@ -102,7 +102,7 @@ default_fill_frame_geometry (MetaFrameInfo *info,
|
||||
pango_layout_set_text (d->layout, info->title, -1);
|
||||
else
|
||||
pango_layout_set_text (d->layout, " ", -1);
|
||||
|
||||
|
||||
pango_layout_get_pixel_extents (d->layout, NULL, &rect);
|
||||
|
||||
d->title_height = rect.height + VERTICAL_TEXT_PAD * 2;
|
||||
|
505
src/uislave.c
505
src/uislave.c
@ -20,10 +20,513 @@
|
||||
*/
|
||||
|
||||
#include "uislave.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READ_FAILED = 0, /* FALSE */
|
||||
READ_OK,
|
||||
READ_EOF
|
||||
} ReadResult;
|
||||
|
||||
static void respawn_child (MetaUISlave *uislave);
|
||||
static gboolean output_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data);
|
||||
static gboolean error_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data);
|
||||
static void kill_child (MetaUISlave *uislave);
|
||||
static void reset_vals (MetaUISlave *uislave);
|
||||
static ReadResult read_data (GString *str,
|
||||
gint fd);
|
||||
|
||||
/* Message queue main loop source */
|
||||
static gboolean mq_prepare (GSource *source,
|
||||
gint *timeout);
|
||||
static gboolean mq_check (GSource *source);
|
||||
static gboolean mq_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
static void mq_destroy (GSource *source);
|
||||
|
||||
static GSourceFuncs mq_funcs = {
|
||||
mq_prepare,
|
||||
mq_check,
|
||||
mq_dispatch,
|
||||
mq_destroy
|
||||
};
|
||||
|
||||
MetaUISlave*
|
||||
meta_ui_slave_new (const char *display_name)
|
||||
meta_ui_slave_new (const char *display_name,
|
||||
MetaUISlaveFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
GSource *source;
|
||||
|
||||
source = g_source_new (&mq_funcs, sizeof (MetaUISlave));
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
uislave->display_name = g_strdup (display_name);
|
||||
uislave->queue = g_queue_new ();
|
||||
uislave->buf = g_string_new ("");
|
||||
uislave->current_message = g_string_new ("");
|
||||
|
||||
reset_vals (uislave);
|
||||
|
||||
/* This may fail; all UISlave functions become no-ops
|
||||
* if uislave->child_pids == 0, and metacity just runs
|
||||
* with no UI features other than window borders.
|
||||
*/
|
||||
respawn_child (uislave);
|
||||
|
||||
g_source_set_priority (source, G_PRIORITY_DEFAULT);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
|
||||
g_source_set_callback (source, (GSourceFunc) func, data, NULL);
|
||||
|
||||
g_source_attach (source, NULL);
|
||||
|
||||
return uislave;
|
||||
}
|
||||
|
||||
void
|
||||
meta_ui_slave_free (MetaUISlave *uislave)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
source = (GSource*) uislave;
|
||||
|
||||
g_source_destroy (source);
|
||||
}
|
||||
|
||||
void
|
||||
meta_ui_slave_disable (MetaUISlave *uislave)
|
||||
{
|
||||
/* Change UI slave into "black hole" mode,
|
||||
* we found out it's hosed for some reason.
|
||||
*/
|
||||
kill_child (uislave);
|
||||
uislave->no_respawn = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
respawn_child (MetaUISlave *uislave)
|
||||
{
|
||||
GError *error;
|
||||
const char *uislavedir;
|
||||
char *argv[] = { "./metacity-uislave", NULL };
|
||||
char *envp[2] = { NULL, NULL };
|
||||
int child_pid, inpipe, outpipe, errpipe;
|
||||
|
||||
if (uislave->no_respawn)
|
||||
return;
|
||||
|
||||
uislavedir = g_getenv ("METACITY_UISLAVE_DIR");
|
||||
if (uislavedir == NULL)
|
||||
uislavedir = METACITY_LIBEXECDIR;
|
||||
|
||||
envp[0] = g_strconcat ("DISPLAY=", uislave->display_name, NULL);
|
||||
|
||||
error = NULL;
|
||||
if (g_spawn_async_with_pipes (uislavedir,
|
||||
argv,
|
||||
envp,
|
||||
/* flags */
|
||||
0,
|
||||
/* setup func, data */
|
||||
NULL, NULL,
|
||||
&child_pid,
|
||||
&inpipe, &outpipe, &errpipe,
|
||||
&error))
|
||||
{
|
||||
uislave->child_pid = child_pid;
|
||||
uislave->in_pipe = inpipe;
|
||||
uislave->err_pipe = errpipe;
|
||||
uislave->out_poll.fd = outpipe;
|
||||
uislave->out_poll.events = G_IO_IN;
|
||||
|
||||
uislave->err_channel = g_io_channel_unix_new (errpipe);
|
||||
|
||||
uislave->errwatch = g_io_add_watch (uislave->err_channel,
|
||||
G_IO_IN,
|
||||
error_callback,
|
||||
uislave);
|
||||
|
||||
meta_verbose ("Spawned UI slave with PID %d\n", uislave->child_pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_warning ("Failed to create user interface process: %s\n",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (envp[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
append_pending (MetaUISlave *uislave)
|
||||
{
|
||||
int needed;
|
||||
|
||||
needed = uislave->current_required_len - uislave->current_message->len;
|
||||
g_assert (needed >= 0);
|
||||
|
||||
needed = MIN (needed, uislave->buf->len);
|
||||
|
||||
/* Move data from buf to current_message */
|
||||
g_string_append_len (uislave->current_message,
|
||||
uislave->buf->str,
|
||||
needed);
|
||||
g_string_erase (uislave->buf,
|
||||
0, needed);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
/* Read messages from slave */
|
||||
MetaUISlave *uislave;
|
||||
ReadResult res;
|
||||
|
||||
uislave = data;
|
||||
|
||||
res = read_data (uislave->buf, uislave->out_pipe);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case READ_OK:
|
||||
meta_verbose ("Read data from slave, %d bytes in buffer\n",
|
||||
uislave->buf->len);
|
||||
break;
|
||||
case READ_EOF:
|
||||
meta_verbose ("EOF reading stdout from slave process\n");
|
||||
break;
|
||||
|
||||
case READ_FAILED:
|
||||
/* read_data printed the error */
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
error_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
/* Relay slave errors to WM stderr */
|
||||
#define BUFSIZE 1024
|
||||
MetaUISlave *uislave;
|
||||
char buf[1024];
|
||||
int n;
|
||||
|
||||
uislave = data;
|
||||
|
||||
/* Classic loop from Stevens */
|
||||
n = read (uislave->err_pipe, buf, BUFSIZE);
|
||||
if (n > 0)
|
||||
{
|
||||
if (write (2, buf, n) != n)
|
||||
; /* error, but printing a message to stderr will hardly help. */
|
||||
}
|
||||
else if (n < 0)
|
||||
meta_warning (_("Error reading errors from UI slave: %s\n"),
|
||||
g_strerror (errno));
|
||||
|
||||
return TRUE;
|
||||
#undef BUFSIZE
|
||||
}
|
||||
|
||||
static void
|
||||
mq_queue_messages (MetaUISlave *uislave)
|
||||
{
|
||||
if (uislave->buf->len == 0)
|
||||
return;
|
||||
|
||||
if (uislave->current_message->len > 0)
|
||||
{
|
||||
/* We had a pending message. */
|
||||
append_pending (uislave);
|
||||
}
|
||||
else if (uislave->buf->len > META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* See if we can start a current message */
|
||||
const char *p;
|
||||
int esc_pos;
|
||||
const char *esc;
|
||||
MetaMessageHeader header;
|
||||
|
||||
/* note that the string from the UI slave includes the nul byte */
|
||||
esc = META_MESSAGE_ESCAPE;
|
||||
|
||||
esc_pos = 0;
|
||||
p = uislave->buf->str;
|
||||
while (p != (uislave->buf->str + uislave->buf->len) &&
|
||||
esc_pos < META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
if (*p != esc[esc_pos])
|
||||
esc_pos = 0;
|
||||
else
|
||||
++esc_pos;
|
||||
|
||||
++p;
|
||||
}
|
||||
|
||||
if (esc_pos == META_MESSAGE_ESCAPE_LEN)
|
||||
{
|
||||
/* We found an entire escape sequence; can safely toss
|
||||
* out the entire buffer before it
|
||||
*/
|
||||
int ignored;
|
||||
|
||||
ignored = p - uislave->buf->str;
|
||||
ignored -= META_MESSAGE_ESCAPE_LEN;
|
||||
|
||||
g_assert (ignored >= 0);
|
||||
|
||||
if (ignored > 0)
|
||||
{
|
||||
meta_verbose ("Ignoring %d bytes from UI slave\n",
|
||||
ignored);
|
||||
|
||||
g_string_erase (uislave->buf, 0, ignored);
|
||||
}
|
||||
}
|
||||
else if (esc_pos == 0)
|
||||
{
|
||||
/* End of buffer doesn't begin an escape sequence;
|
||||
* toss out entire buffer.
|
||||
*/
|
||||
meta_verbose ("Ignoring %d bytes from UI slave\n",
|
||||
uislave->buf->len);
|
||||
g_string_truncate (uislave->buf, 0);
|
||||
}
|
||||
|
||||
if (uislave->buf->len < (META_MESSAGE_ESCAPE_LEN + sizeof (MetaMessageHeader)))
|
||||
return; /* Not enough data yet. */
|
||||
|
||||
memcpy (&header, uislave->buf->str + META_MESSAGE_ESCAPE_LEN, sizeof (MetaMessageHeader));
|
||||
|
||||
/* Length includes the header even though it's in the header. */
|
||||
meta_verbose ("Read header code: %d length: %d from UI slave\n",
|
||||
header.message_code, header.length);
|
||||
|
||||
uislave->current_required_len = header.length;
|
||||
g_string_erase (uislave->buf, 0, META_MESSAGE_ESCAPE_LEN);
|
||||
|
||||
append_pending (uislave);
|
||||
}
|
||||
|
||||
g_assert (uislave->current_message->len <= uislave->current_required_len);
|
||||
|
||||
if (uislave->current_required_len > 0 &&
|
||||
uislave->current_message->len == uislave->current_required_len)
|
||||
{
|
||||
MetaMessage *message;
|
||||
|
||||
message = g_new (MetaMessage, 1);
|
||||
|
||||
memcpy (message,
|
||||
uislave->current_message->str, uislave->current_message->len);
|
||||
|
||||
g_queue_push_tail (uislave->queue, message);
|
||||
|
||||
meta_verbose ("Added %d-byte message to queue\n",
|
||||
uislave->current_message->len);
|
||||
|
||||
uislave->current_required_len = 0;
|
||||
g_string_truncate (uislave->current_message, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_messages_pending (MetaUISlave *uislave)
|
||||
{
|
||||
return uislave->queue->length > 0 || uislave->buf->len > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_prepare (GSource *source, gint *timeout)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
return mq_messages_pending (uislave);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_check (GSource *source)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
return mq_messages_pending (uislave);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
mq_queue_messages (uislave);
|
||||
|
||||
if (uislave->queue->length > 0)
|
||||
{
|
||||
MetaUISlaveFunc func;
|
||||
MetaMessage *msg;
|
||||
static int count = 0;
|
||||
|
||||
++count;
|
||||
|
||||
msg = g_queue_pop_head (uislave->queue);
|
||||
func = (MetaUISlaveFunc) callback;
|
||||
|
||||
(* func) (uislave, msg, user_data);
|
||||
|
||||
meta_verbose ("%d messages dispatched\n", count);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
kill_child (MetaUISlave *uislave)
|
||||
{
|
||||
if (uislave->outwatch != 0)
|
||||
g_source_remove (uislave->outwatch);
|
||||
|
||||
if (uislave->errwatch != 0)
|
||||
g_source_remove (uislave->errwatch);
|
||||
|
||||
if (uislave->out_channel)
|
||||
g_io_channel_unref (uislave->out_channel);
|
||||
|
||||
if (uislave->err_channel)
|
||||
g_io_channel_unref (uislave->err_channel);
|
||||
|
||||
if (uislave->out_pipe >= 0)
|
||||
close (uislave->out_pipe);
|
||||
|
||||
if (uislave->in_pipe >= 0)
|
||||
close (uislave->in_pipe);
|
||||
|
||||
if (uislave->err_pipe >= 0)
|
||||
close (uislave->err_pipe);
|
||||
|
||||
while (uislave->queue->length > 0)
|
||||
{
|
||||
MetaMessage *msg;
|
||||
|
||||
msg = g_queue_pop_head (uislave->queue);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
|
||||
if (uislave->buf->len > 0)
|
||||
g_string_truncate (uislave->buf, 0);
|
||||
|
||||
if (uislave->current_message->len > 0)
|
||||
g_string_truncate (uislave->current_message, 0);
|
||||
|
||||
if (uislave->child_pid > 0)
|
||||
{
|
||||
/* don't care if this fails except in verbose mode */
|
||||
if (kill (uislave->child_pid, SIGTERM) != 0)
|
||||
{
|
||||
meta_verbose ("Kill of UI slave process %d failed: %s\n",
|
||||
uislave->child_pid, g_strerror (errno));
|
||||
}
|
||||
|
||||
uislave->child_pid = 0;
|
||||
}
|
||||
|
||||
reset_vals (uislave);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_vals (MetaUISlave *uislave)
|
||||
{
|
||||
uislave->child_pid = 0;
|
||||
uislave->in_pipe = -1;
|
||||
uislave->out_pipe = -1;
|
||||
uislave->err_pipe = -1;
|
||||
uislave->no_respawn = FALSE;
|
||||
uislave->out_channel = NULL;
|
||||
uislave->err_channel = NULL;
|
||||
uislave->outwatch = 0;
|
||||
uislave->errwatch = 0;
|
||||
uislave->current_required_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mq_destroy (GSource *source)
|
||||
{
|
||||
MetaUISlave *uislave;
|
||||
|
||||
uislave = (MetaUISlave*) source;
|
||||
|
||||
meta_verbose ("Deleting UI slave for display '%s'\n",
|
||||
uislave->display_name);
|
||||
|
||||
kill_child (uislave);
|
||||
|
||||
g_string_free (uislave->buf, TRUE);
|
||||
g_string_free (uislave->current_message, TRUE);
|
||||
|
||||
g_queue_free (uislave->queue);
|
||||
|
||||
g_free (uislave->display_name);
|
||||
|
||||
/* source itself is freed by glib */
|
||||
}
|
||||
|
||||
static ReadResult
|
||||
read_data (GString *str,
|
||||
gint fd)
|
||||
{
|
||||
#define BUFSIZE 16
|
||||
gint bytes;
|
||||
gchar buf[BUFSIZE];
|
||||
|
||||
again:
|
||||
|
||||
bytes = read (fd, &buf, BUFSIZE);
|
||||
|
||||
if (bytes == 0)
|
||||
return READ_EOF;
|
||||
else if (bytes > 0)
|
||||
{
|
||||
g_string_append_len (str, buf, bytes);
|
||||
return READ_OK;
|
||||
}
|
||||
else if (bytes < 0 && errno == EINTR)
|
||||
goto again;
|
||||
else if (bytes < 0)
|
||||
{
|
||||
meta_warning (_("Failed to read data from UI slave: %s\n"),
|
||||
g_strerror (errno));
|
||||
|
||||
return READ_FAILED;
|
||||
}
|
||||
else
|
||||
return READ_OK;
|
||||
}
|
||||
|
@ -23,17 +23,39 @@
|
||||
#define META_UI_SLAVE_H
|
||||
|
||||
#include "util.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include "uislave/messages.h"
|
||||
#include "display.h"
|
||||
|
||||
typedef struct _MetaUISlave MetaUISlave;
|
||||
typedef void (* MetaUISlaveFunc) (MetaUISlave *uislave,
|
||||
MetaMessage *message,
|
||||
gpointer data);
|
||||
|
||||
struct _MetaUISlave
|
||||
{
|
||||
GSource source;
|
||||
|
||||
char *display_name;
|
||||
int child_pid;
|
||||
int in_pipe;
|
||||
int err_pipe;
|
||||
GPollFD out_poll;
|
||||
GIOChannel *err_channel;
|
||||
unsigned int errwatch;
|
||||
GQueue *queue;
|
||||
GString *buf;
|
||||
GString *current_message;
|
||||
int current_required_len;
|
||||
/* if we determine that our available slave is hosed,
|
||||
* set this bit.
|
||||
*/
|
||||
guint no_respawn : 1;
|
||||
};
|
||||
|
||||
MetaUISlave* meta_ui_slave_new (const char *display_name);
|
||||
MetaUISlave* meta_ui_slave_new (const char *display_name,
|
||||
MetaUISlaveFunc func,
|
||||
gpointer data);
|
||||
void meta_ui_slave_free (MetaUISlave *uislave);
|
||||
void meta_ui_slave_disable (MetaUISlave *uislave);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
INCLUDES=@UISLAVE_CFLAGS@
|
||||
INCLUDES=@UISLAVE_CFLAGS@ -DHOST_ALIAS=\"@HOST_ALIAS@\"
|
||||
|
||||
metacity_uislave_SOURCES = \
|
||||
main.c
|
||||
metacity_uislave_SOURCES = \
|
||||
main.c \
|
||||
messages.c \
|
||||
messages.h
|
||||
|
||||
libexec_PROGRAMS=metacity-uislave
|
||||
|
||||
|
@ -19,9 +19,75 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "messages.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void
|
||||
meta_ui_warning (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
gchar *str;
|
||||
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
va_start (args, format);
|
||||
str = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
fputs (str, stderr);
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* report our nature to the window manager */
|
||||
meta_message_send_check ();
|
||||
|
||||
#if 1
|
||||
/* Try breaking message queue system. */
|
||||
i = 0;
|
||||
while (i < 100)
|
||||
{
|
||||
meta_message_send_check ();
|
||||
if (g_random_boolean ())
|
||||
{
|
||||
int j;
|
||||
if (g_random_boolean ())
|
||||
j = g_random_int_range (0, 15);
|
||||
else
|
||||
j = g_random_int_range (0, 1000);
|
||||
while (j > 0)
|
||||
{
|
||||
char b;
|
||||
b = g_random_int_range (0, 256);
|
||||
|
||||
write (1, &b, 1);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
#endif
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
123
src/uislave/messages.c
Normal file
123
src/uislave/messages.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* Metacity UI Slave Messages */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* 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 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "messages.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <config.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READ_FAILED = 0, /* FALSE */
|
||||
READ_OK,
|
||||
READ_EOF
|
||||
} ReadResult;
|
||||
|
||||
static ReadResult read_data (GString *str,
|
||||
gint fd);
|
||||
|
||||
static void send_message (MetaMessage *message);
|
||||
|
||||
void
|
||||
meta_message_send_check (void)
|
||||
{
|
||||
MetaMessageCheck check;
|
||||
|
||||
memset (&check, 0, sizeof (check));
|
||||
check.header.message_code = MetaMessageCheckCode;
|
||||
check.header.length = sizeof (check);
|
||||
strcpy (check.metacity_version, VERSION);
|
||||
strcpy (check.host_alias, HOST_ALIAS);
|
||||
check.metacity_version[META_MESSAGE_MAX_VERSION_LEN] = '\0';
|
||||
check.host_alias[META_MESSAGE_MAX_HOST_ALIAS_LEN] = '\0';
|
||||
check.messages_version = META_MESSAGES_VERSION;
|
||||
|
||||
send_message ((MetaMessage*)&check);
|
||||
}
|
||||
|
||||
static int
|
||||
write_bytes (void *buf, int bytes)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = (char*) buf;
|
||||
while (bytes > 0)
|
||||
{
|
||||
int written;
|
||||
|
||||
written = write (1, p, bytes);
|
||||
|
||||
if (written < 0)
|
||||
return -1;
|
||||
|
||||
bytes -= written;
|
||||
p += written;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
send_message (MetaMessage *message)
|
||||
{
|
||||
/* Not much point checking for errors here. We can't
|
||||
* really report them anyway.
|
||||
*/
|
||||
|
||||
write_bytes (META_MESSAGE_ESCAPE, META_MESSAGE_ESCAPE_LEN);
|
||||
write_bytes (message, message->header.length);
|
||||
}
|
||||
|
||||
static ReadResult
|
||||
read_data (GString *str,
|
||||
gint fd)
|
||||
{
|
||||
gint bytes;
|
||||
gchar buf[4096];
|
||||
|
||||
again:
|
||||
|
||||
bytes = read (fd, &buf, 4096);
|
||||
|
||||
if (bytes == 0)
|
||||
return READ_EOF;
|
||||
else if (bytes > 0)
|
||||
{
|
||||
g_string_append_len (str, buf, bytes);
|
||||
return READ_OK;
|
||||
}
|
||||
else if (bytes < 0 && errno == EINTR)
|
||||
goto again;
|
||||
else if (bytes < 0)
|
||||
{
|
||||
meta_ui_warning (_("Failed to read data from window manager (%s)\n"),
|
||||
g_strerror (errno));
|
||||
|
||||
return READ_FAILED;
|
||||
}
|
||||
else
|
||||
return READ_OK;
|
||||
}
|
115
src/uislave/messages.h
Normal file
115
src/uislave/messages.h
Normal file
@ -0,0 +1,115 @@
|
||||
/* Metacity UI Slave Messages */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* 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 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_UI_SLAVE_MESSAGES_H
|
||||
#define META_UI_SLAVE_MESSAGES_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/* This header is shared between the WM and the UI slave */
|
||||
/* Note that our IPC can be kind of lame; we trust both sides
|
||||
* of the connection, and assume that they were compiled at the
|
||||
* same time vs. the same libs on the same arch
|
||||
*/
|
||||
|
||||
/* We increment this when we change this header, so we can
|
||||
* check for mismatched UI slave and WM
|
||||
*/
|
||||
#define META_MESSAGES_VERSION 1
|
||||
|
||||
/* We have an escape sequence, just in case some part of GTK
|
||||
* decides to write to stdout, so that we have a good chance
|
||||
* of surviving that. GTK probably won't print this string.
|
||||
* This string has to stay the same always so we can ping
|
||||
* old UI slaves.
|
||||
*/
|
||||
#define META_MESSAGE_ESCAPE "|~-metacity-~|"
|
||||
/* len includes nul byte which is a required part of the escape */
|
||||
#define META_MESSAGE_ESCAPE_LEN 15
|
||||
|
||||
#define META_MESSAGE_MAX_VERSION_LEN 15
|
||||
#define META_MESSAGE_MAX_HOST_ALIAS_LEN 50
|
||||
|
||||
typedef union _MetaMessage MetaMessage;
|
||||
typedef struct _MetaMessageHeader MetaMessageHeader;
|
||||
typedef struct _MetaMessageCheck MetaMessageCheck;
|
||||
typedef struct _MetaMessageShowTip MetaMessageShowTip;
|
||||
typedef struct _MetaMessageHideTip MetaMessageHideTip;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Keep NullCode and CheckCode unchanged, as with the escape sequence,
|
||||
* so we can check old UI slaves.
|
||||
*/
|
||||
MetaMessageNullCode,
|
||||
MetaMessageCheckCode,
|
||||
MetaMessageShowTipCode,
|
||||
MetaMessageHideTipCode
|
||||
} MetaMessageCode;
|
||||
|
||||
struct _MetaMessageHeader
|
||||
{
|
||||
MetaMessageCode message_code;
|
||||
int length;
|
||||
};
|
||||
|
||||
/* just a ping to see if we have the right
|
||||
* version of UI slave.
|
||||
*/
|
||||
struct _MetaMessageCheck
|
||||
{
|
||||
MetaMessageHeader header;
|
||||
|
||||
/* it's OK if the max sizes aren't large enough in all cases, these
|
||||
* are just paranoia checks
|
||||
*/
|
||||
char metacity_version[META_MESSAGE_MAX_VERSION_LEN + 1];
|
||||
char host_alias[META_MESSAGE_MAX_HOST_ALIAS_LEN + 1];
|
||||
int messages_version;
|
||||
};
|
||||
|
||||
struct _MetaMessageShowTip
|
||||
{
|
||||
MetaMessageHeader header;
|
||||
int root_x;
|
||||
int root_y;
|
||||
/* Then a nul-terminated string follows */
|
||||
};
|
||||
|
||||
struct _MetaMessageHideTip
|
||||
{
|
||||
MetaMessageHeader header;
|
||||
/* just hides the current tip */
|
||||
};
|
||||
|
||||
union _MetaMessage
|
||||
{
|
||||
MetaMessageHeader header;
|
||||
MetaMessageCheck check;
|
||||
MetaMessageShowTip show_tip;
|
||||
MetaMessageShowTip hide_tip;
|
||||
};
|
||||
|
||||
/* Slave-side message send/read code */
|
||||
|
||||
void meta_message_send_check (void);
|
||||
|
||||
#endif
|
@ -54,6 +54,7 @@ void meta_fatal (const char *format,
|
||||
...) G_GNUC_PRINTF (1, 2);
|
||||
|
||||
/* FIXME */
|
||||
#include <config.h>
|
||||
#define _(x) x
|
||||
|
||||
#endif
|
||||
|
332
src/window.c
332
src/window.c
@ -34,13 +34,11 @@ static int update_size_hints (MetaWindow *window);
|
||||
static int update_title (MetaWindow *window);
|
||||
static int update_protocols (MetaWindow *window);
|
||||
static gboolean process_configure_request (MetaWindow *window,
|
||||
XConfigureRequestEvent *event);
|
||||
int x, int y, int width, int height,
|
||||
int border_width);
|
||||
static gboolean process_property_notify (MetaWindow *window,
|
||||
XPropertyEvent *event);
|
||||
|
||||
|
||||
|
||||
|
||||
MetaWindow*
|
||||
meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
{
|
||||
@ -57,9 +55,7 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
xwindow, &attrs) == Success &&
|
||||
attrs.override_redirect)
|
||||
{
|
||||
/* Oops. Probably attempted to manage override redirect window
|
||||
* in initial screen_manage_all_windows() call.
|
||||
*/
|
||||
meta_verbose ("Deciding not to manage override_redirect window 0x%lx\n", xwindow);
|
||||
meta_error_trap_pop (display);
|
||||
return NULL;
|
||||
}
|
||||
@ -67,7 +63,7 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
XAddToSaveSet (display->xdisplay, xwindow);
|
||||
|
||||
XSelectInput (display->xdisplay, xwindow,
|
||||
StructureNotifyMask);
|
||||
PropertyChangeMask);
|
||||
|
||||
if (meta_error_trap_pop (display) != Success)
|
||||
{
|
||||
@ -105,6 +101,12 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
window->rect.y = attrs.y;
|
||||
window->rect.width = attrs.width;
|
||||
window->rect.height = attrs.height;
|
||||
|
||||
window->size_hints.x = attrs.x;
|
||||
window->size_hints.y = attrs.y;
|
||||
window->size_hints.width = attrs.width;
|
||||
window->size_hints.height = attrs.height;
|
||||
|
||||
window->depth = attrs.depth;
|
||||
window->xvisual = attrs.visual;
|
||||
|
||||
@ -112,14 +114,17 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
window->iconic = FALSE;
|
||||
|
||||
window->desc = g_strdup_printf ("0x%lx", window->xwindow);
|
||||
|
||||
window->frame = NULL;
|
||||
|
||||
meta_display_register_x_window (display, &window->xwindow, window);
|
||||
|
||||
update_size_hints (window);
|
||||
update_title (window);
|
||||
update_protocols (window);
|
||||
update_protocols (window);
|
||||
|
||||
meta_window_resize (window, window->size_hints.width, window->size_hints.height);
|
||||
|
||||
window->frame = NULL;
|
||||
meta_window_ensure_frame (window);
|
||||
|
||||
return window;
|
||||
@ -132,10 +137,10 @@ meta_window_free (MetaWindow *window)
|
||||
|
||||
meta_display_unregister_x_window (window->display, window->xwindow);
|
||||
|
||||
g_free (window->title);
|
||||
|
||||
meta_window_destroy_frame (window);
|
||||
|
||||
g_free (window->title);
|
||||
g_free (window->desc);
|
||||
g_free (window);
|
||||
}
|
||||
|
||||
@ -159,13 +164,56 @@ meta_window_hide (MetaWindow *window)
|
||||
window->iconic = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_resize (MetaWindow *window,
|
||||
int w,
|
||||
int h)
|
||||
{
|
||||
meta_verbose ("Resizing %s to %d x %d\n", window->desc, w, h);
|
||||
constrain_size (window, w, h, &w, &h);
|
||||
meta_verbose ("Constrained resize of %s to %d x %d\n", window->desc, w, h);
|
||||
|
||||
if (w != window->rect.width ||
|
||||
h != window->rect.height)
|
||||
{
|
||||
meta_error_trap_push (window->display);
|
||||
XResizeWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
w, h);
|
||||
meta_error_trap_pop (window->display);
|
||||
window->rect.width = w;
|
||||
window->rect.height = h;
|
||||
|
||||
if (window->frame)
|
||||
meta_frame_queue_recalc (window->frame);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_window_configure_request (MetaWindow *window,
|
||||
XEvent *event)
|
||||
{
|
||||
return process_configure_request (window,
|
||||
event->xconfigurerequest.x,
|
||||
event->xconfigurerequest.y,
|
||||
event->xconfigurerequest.width,
|
||||
event->xconfigurerequest.height,
|
||||
event->xconfigurerequest.border_width);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_window_property_notify (MetaWindow *window,
|
||||
XEvent *event)
|
||||
{
|
||||
return process_property_notify (window, &event->xproperty);
|
||||
}
|
||||
|
||||
|
||||
|
||||
gboolean
|
||||
meta_window_event (MetaWindow *window,
|
||||
XEvent *event)
|
||||
{
|
||||
if (window->frame &&
|
||||
event->xany.window == window->frame->xwindow)
|
||||
return meta_frame_event (window->frame, event);
|
||||
|
||||
if (event->xany.window != window->xwindow)
|
||||
return FALSE;
|
||||
@ -203,7 +251,7 @@ meta_window_event (MetaWindow *window,
|
||||
case CreateNotify:
|
||||
break;
|
||||
case DestroyNotify:
|
||||
meta_window_free (window);
|
||||
|
||||
return TRUE;
|
||||
break;
|
||||
case UnmapNotify:
|
||||
@ -218,17 +266,10 @@ meta_window_event (MetaWindow *window,
|
||||
case ReparentNotify:
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
if (event->xconfigure.override_redirect)
|
||||
{
|
||||
/* Unmanage it, override_redirect was toggled on?
|
||||
* Can this happen?
|
||||
*/
|
||||
meta_window_free (window);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
case ConfigureRequest:
|
||||
return process_configure_request (window, &event->xconfigurerequest);
|
||||
|
||||
break;
|
||||
case GravityNotify:
|
||||
break;
|
||||
@ -239,7 +280,7 @@ meta_window_event (MetaWindow *window,
|
||||
case CirculateRequest:
|
||||
break;
|
||||
case PropertyNotify:
|
||||
return process_property_notify (window, &event->xproperty);
|
||||
|
||||
break;
|
||||
case SelectionClear:
|
||||
break;
|
||||
@ -269,39 +310,160 @@ process_property_notify (MetaWindow *window,
|
||||
event->atom == window->display->atom_net_wm_name)
|
||||
{
|
||||
update_title (window);
|
||||
|
||||
if (window->frame)
|
||||
meta_frame_queue_recalc (window->frame);
|
||||
}
|
||||
else if (event->atom == XA_WM_NORMAL_HINTS)
|
||||
{
|
||||
update_size_hints (window);
|
||||
|
||||
/* See if we need to constrain current size */
|
||||
meta_window_resize (window, window->rect.width, window->rect.height);
|
||||
}
|
||||
else if (event->atom == XA_WM_PROTOCOLS)
|
||||
else if (event->atom == window->display->atom_wm_protocols)
|
||||
{
|
||||
update_protocols (window);
|
||||
|
||||
if (window->frame)
|
||||
meta_frame_queue_recalc (window->frame);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
send_configure_notify (MetaWindow *window)
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
/* from twm */
|
||||
|
||||
event.type = ConfigureNotify;
|
||||
event.xconfigure.display = window->display->xdisplay;
|
||||
event.xconfigure.event = window->xwindow;
|
||||
event.xconfigure.window = window->xwindow;
|
||||
event.xconfigure.x = window->rect.x - window->border_width;
|
||||
event.xconfigure.y = window->rect.y - window->border_width;
|
||||
if (window->frame)
|
||||
{
|
||||
/* Need to be in root window coordinates */
|
||||
event.xconfigure.x += window->frame->rect.x;
|
||||
event.xconfigure.y += window->frame->rect.y;
|
||||
}
|
||||
event.xconfigure.width = window->rect.width;
|
||||
event.xconfigure.height = window->rect.height;
|
||||
event.xconfigure.border_width = window->border_width; /* requested not actual */
|
||||
event.xconfigure.above = None; /* FIXME */
|
||||
event.xconfigure.override_redirect = False;
|
||||
|
||||
meta_verbose ("Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n",
|
||||
window->desc,
|
||||
event.xconfigure.x, event.xconfigure.y,
|
||||
event.xconfigure.width, event.xconfigure.height);
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
XSendEvent(window->display->xdisplay,
|
||||
window->xwindow,
|
||||
False, StructureNotifyMask, &event);
|
||||
meta_error_trap_pop (window->display);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_configure_request (MetaWindow *window,
|
||||
XConfigureRequestEvent *event)
|
||||
process_configure_request (MetaWindow *window,
|
||||
int x, int y,
|
||||
int width, int height,
|
||||
int border_width)
|
||||
{
|
||||
/* ICCCM 4.1.5 */
|
||||
|
||||
XWindowChanges values;
|
||||
unsigned int mask;
|
||||
int client_x, client_y;
|
||||
|
||||
/* Note that x, y is the corner of the window border,
|
||||
* and width, height is the size of the window inside
|
||||
* its border, but that we always deny border requests
|
||||
* because we don't believe in clients who use lame-ass
|
||||
* X features like that.
|
||||
*/
|
||||
window->border_width = event->border_width;
|
||||
window->size_hints.x = event->x;
|
||||
window->size_hints.y = event->y;
|
||||
window->size_hints.width = event->width;
|
||||
window->size_hints.height = event->height;
|
||||
window->border_width = border_width;
|
||||
|
||||
/* FIXME */
|
||||
/* We're ignoring the value_mask here, since sizes
|
||||
* not in the mask will be the current window geometry.
|
||||
*/
|
||||
|
||||
window->size_hints.x = x;
|
||||
window->size_hints.y = y;
|
||||
window->size_hints.width = width;
|
||||
window->size_hints.height = height;
|
||||
|
||||
constrain_size (window,
|
||||
window->size_hints.width,
|
||||
window->size_hints.height,
|
||||
&window->size_hints.width,
|
||||
&window->size_hints.height);
|
||||
|
||||
meta_verbose ("Constrained configure request size to %d x %d\n",
|
||||
window->size_hints.width, window->size_hints.height);
|
||||
|
||||
if (window->frame)
|
||||
{
|
||||
meta_frame_child_configure_request (window->frame);
|
||||
client_x = window->frame->child_x;
|
||||
client_y = window->frame->child_y;
|
||||
meta_verbose ("Will place client window %s inside frame at %d,%d\n",
|
||||
window->desc, client_x, client_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
client_x = window->size_hints.x;
|
||||
client_y = window->size_hints.y;
|
||||
meta_verbose ("Will place client window %s at root coordinate %d,%d\n",
|
||||
window->desc, client_x, client_y);
|
||||
}
|
||||
|
||||
values.border_width = 0;
|
||||
values.x = client_x;
|
||||
values.y = client_y;
|
||||
values.width = window->size_hints.width;
|
||||
values.height = window->size_hints.height;
|
||||
|
||||
mask = 0;
|
||||
if (window->border_width != 0)
|
||||
mask |= CWBorderWidth;
|
||||
if (values.x != window->rect.x)
|
||||
mask |= CWX;
|
||||
if (values.y != window->rect.y)
|
||||
mask |= CWY;
|
||||
if (values.width != window->rect.width)
|
||||
mask |= CWWidth;
|
||||
if (values.height != window->rect.height)
|
||||
mask |= CWHeight;
|
||||
|
||||
window->rect.x = values.x;
|
||||
window->rect.y = values.y;
|
||||
window->rect.width = values.width;
|
||||
window->rect.height = values.height;
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
XConfigureWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
mask,
|
||||
&values);
|
||||
meta_error_trap_pop (window->display);
|
||||
|
||||
if (mask & (CWBorderWidth | CWWidth | CWHeight))
|
||||
{
|
||||
/* Resizing, no synthetic ConfigureNotify, third case in 4.1.5 */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Moving but not resizing, second case in 4.1.5, or
|
||||
* have to send the ConfigureNotify, first case in 4.1.5
|
||||
*/
|
||||
send_configure_notify (window);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -333,7 +495,12 @@ update_size_hints (MetaWindow *window)
|
||||
window->size_hints.height = h;
|
||||
|
||||
if (window->size_hints.flags & PBaseSize)
|
||||
;
|
||||
{
|
||||
meta_verbose ("Window %s sets base size %d x %d\n",
|
||||
window->desc,
|
||||
window->size_hints.base_width,
|
||||
window->size_hints.base_height);
|
||||
}
|
||||
else if (window->size_hints.flags & PMinSize)
|
||||
{
|
||||
window->size_hints.base_width = window->size_hints.min_width;
|
||||
@ -347,7 +514,12 @@ update_size_hints (MetaWindow *window)
|
||||
window->size_hints.flags |= PBaseSize;
|
||||
|
||||
if (window->size_hints.flags & PMinSize)
|
||||
;
|
||||
{
|
||||
meta_verbose ("Window %s sets min size %d x %d\n",
|
||||
window->desc,
|
||||
window->size_hints.min_width,
|
||||
window->size_hints.min_height);
|
||||
}
|
||||
else if (window->size_hints.flags & PBaseSize)
|
||||
{
|
||||
window->size_hints.min_width = window->size_hints.base_width;
|
||||
@ -361,7 +533,12 @@ update_size_hints (MetaWindow *window)
|
||||
window->size_hints.flags |= PMinSize;
|
||||
|
||||
if (window->size_hints.flags & PMaxSize)
|
||||
;
|
||||
{
|
||||
meta_verbose ("Window %s sets max size %d x %d\n",
|
||||
window->desc,
|
||||
window->size_hints.max_width,
|
||||
window->size_hints.max_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->size_hints.max_width = G_MAXINT;
|
||||
@ -370,7 +547,22 @@ update_size_hints (MetaWindow *window)
|
||||
}
|
||||
|
||||
if (window->size_hints.flags & PResizeInc)
|
||||
;
|
||||
{
|
||||
meta_verbose ("Window %s sets resize width inc: %d height inc: %d\n",
|
||||
window->desc,
|
||||
window->size_hints.width_inc,
|
||||
window->size_hints.height_inc);
|
||||
if (window->size_hints.width_inc == 0)
|
||||
{
|
||||
window->size_hints.width_inc = 1;
|
||||
meta_verbose ("Corrected 0 width_inc to 1\n");
|
||||
}
|
||||
if (window->size_hints.height_inc == 0)
|
||||
{
|
||||
window->size_hints.height_inc = 1;
|
||||
meta_verbose ("Corrected 0 height_inc to 1\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window->size_hints.width_inc = 1;
|
||||
@ -380,6 +572,13 @@ update_size_hints (MetaWindow *window)
|
||||
|
||||
if (window->size_hints.flags & PAspect)
|
||||
{
|
||||
meta_verbose ("Window %s sets min_aspect: %d/%d max_aspect: %d/%d\n",
|
||||
window->desc,
|
||||
window->size_hints.min_aspect.x,
|
||||
window->size_hints.min_aspect.y,
|
||||
window->size_hints.max_aspect.x,
|
||||
window->size_hints.max_aspect.y);
|
||||
|
||||
/* don't divide by 0 */
|
||||
if (window->size_hints.min_aspect.y < 1)
|
||||
window->size_hints.min_aspect.y = 1;
|
||||
@ -396,14 +595,16 @@ update_size_hints (MetaWindow *window)
|
||||
}
|
||||
|
||||
if (window->size_hints.flags & PWinGravity)
|
||||
;
|
||||
{
|
||||
meta_verbose ("Window %s sets gravity %d\n",
|
||||
window->desc,
|
||||
window->size_hints.win_gravity);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->size_hints.win_gravity = NorthWestGravity;
|
||||
window->size_hints.flags |= PWinGravity;
|
||||
}
|
||||
|
||||
/* FIXME constrain the window to these hints */
|
||||
|
||||
return meta_error_trap_pop (window->display);
|
||||
}
|
||||
@ -480,38 +681,44 @@ update_title (MetaWindow *window)
|
||||
window->title = g_strdup ("");
|
||||
|
||||
window->desc = g_strdup_printf ("0x%lx (%.10s)", window->xwindow, window->title);
|
||||
|
||||
|
||||
return meta_error_trap_pop (window->display);
|
||||
}
|
||||
|
||||
static int
|
||||
update_protocols (MetaWindow *window)
|
||||
{
|
||||
Atom *protocols;
|
||||
int n_protocols;
|
||||
Atom *protocols = NULL;
|
||||
int n_protocols = 0;
|
||||
int i;
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
XGetWMProtocols (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
&protocols,
|
||||
&n_protocols);
|
||||
|
||||
window->take_focus = FALSE;
|
||||
window->delete_window = FALSE;
|
||||
i = 0;
|
||||
while (i < n_protocols)
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
|
||||
if (XGetWMProtocols (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
&protocols,
|
||||
&n_protocols) == Success)
|
||||
{
|
||||
if (protocols[i] == _XA_WM_TAKE_FOCUS)
|
||||
window->takes_focus = TRUE;
|
||||
else if (protocols[i] == _XA_WM_DELETE_WINDOW)
|
||||
window->delete_window = TRUE;
|
||||
++i;
|
||||
i = 0;
|
||||
while (i < n_protocols)
|
||||
{
|
||||
if (protocols[i] == window->display->atom_wm_take_focus)
|
||||
window->take_focus = TRUE;
|
||||
else if (protocols[i] == window->display->atom_wm_delete_window)
|
||||
window->delete_window = TRUE;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (protocols)
|
||||
XFree (protocols);
|
||||
}
|
||||
|
||||
if (protocols)
|
||||
XFree (protocols);
|
||||
|
||||
meta_verbose ("Window %s has take_focus = %d delete_window = %d\n",
|
||||
window->desc, window->take_focus, window->delete_window);
|
||||
|
||||
return meta_error_trap_pop (window->display);
|
||||
}
|
||||
|
||||
@ -591,3 +798,4 @@ constrain_size (MetaWindow *window,
|
||||
*new_width = width;
|
||||
*new_height = height;
|
||||
}
|
||||
|
||||
|
21
src/window.h
21
src/window.h
@ -51,14 +51,21 @@ struct _MetaWindow
|
||||
XSizeHints size_hints;
|
||||
};
|
||||
|
||||
MetaWindow* meta_window_new (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
void meta_window_free (MetaWindow *window);
|
||||
void meta_window_show (MetaWindow *window);
|
||||
void meta_window_hide (MetaWindow *window);
|
||||
MetaWindow* meta_window_new (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
void meta_window_free (MetaWindow *window);
|
||||
void meta_window_show (MetaWindow *window);
|
||||
void meta_window_hide (MetaWindow *window);
|
||||
void meta_window_resize (MetaWindow *window,
|
||||
int w,
|
||||
int h);
|
||||
|
||||
gboolean meta_window_configure_request (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_property_notify (MetaWindow *window,
|
||||
XEvent *event);
|
||||
|
||||
|
||||
gboolean meta_window_event (MetaWindow *window,
|
||||
XEvent *event);
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user