This commit is contained in:
rhp 2001-06-30 23:17:52 +00:00
parent ed2af7d22f
commit 43f807c5e1
25 changed files with 487 additions and 3484 deletions

View File

@ -73,7 +73,6 @@ Makefile
intl/Makefile intl/Makefile
po/Makefile.in po/Makefile.in
src/Makefile src/Makefile
src/uislave/Makefile
]) ])

View File

@ -3,5 +3,3 @@ Makefile.in
Makefile Makefile
.deps .deps
metacity metacity
messagequeue.h
messagequeue.c

View File

@ -10,6 +10,8 @@ metacity_SOURCES= \
errors.h \ errors.h \
eventqueue.c \ eventqueue.c \
eventqueue.h \ eventqueue.h \
fixedtip.c \
fixedtip.h \
frame.c \ frame.c \
frame.h \ frame.h \
frames.c \ frames.c \

View File

@ -98,6 +98,7 @@ meta_core_user_move (Display *xdisplay,
void void
meta_core_user_resize (Display *xdisplay, meta_core_user_resize (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
int gravity,
int width, int width,
int height) int height)
{ {
@ -111,7 +112,7 @@ meta_core_user_resize (Display *xdisplay,
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
window->user_has_resized = TRUE; window->user_has_resized = TRUE;
meta_window_resize (window, width, height); meta_window_resize_with_gravity (window, width, height, gravity);
} }
void void
@ -375,4 +376,3 @@ meta_core_show_window_menu (Display *xdisplay,
meta_window_show_menu (window, root_x, root_y, button, timestamp); meta_window_show_menu (window, root_x, root_y, button, timestamp);
} }

View File

@ -46,6 +46,7 @@ void meta_core_user_move (Display *xdisplay,
int y); int y);
void meta_core_user_resize (Display *xdisplay, void meta_core_user_resize (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
int gravity,
int width, int width,
int height); int height);
@ -84,7 +85,6 @@ void meta_core_change_workspace (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
int new_workspace); int new_workspace);
int meta_core_get_num_workspaces (Screen *xscreen); int meta_core_get_num_workspaces (Screen *xscreen);
int meta_core_get_active_workspace (Screen *xscreen); int meta_core_get_active_workspace (Screen *xscreen);
int meta_core_get_frame_workspace (Display *xdisplay, int meta_core_get_frame_workspace (Display *xdisplay,

View File

@ -36,7 +36,8 @@ expose_handler (GtkTooltips *tooltips)
} }
void void
meta_fixed_tip_show (int root_x, int root_y, meta_fixed_tip_show (Display *xdisplay,
int root_x, int root_y,
const char *markup_text) const char *markup_text)
{ {
if (tip == NULL) if (tip == NULL)
@ -74,5 +75,9 @@ meta_fixed_tip_show (int root_x, int root_y,
void void
meta_fixed_tip_hide (void) meta_fixed_tip_hide (void)
{ {
if (tip)
{
gtk_widget_destroy (tip); gtk_widget_destroy (tip);
tip = NULL;
}
} }

View File

@ -23,8 +23,10 @@
#define META_FIXED_TIP_H #define META_FIXED_TIP_H
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gdk/gdkx.h>
void meta_fixed_tip_show (int root_x, int root_y, void meta_fixed_tip_show (Display *xdisplay,
int root_x, int root_y,
const char *markup_text); const char *markup_text);
void meta_fixed_tip_hide (void); void meta_fixed_tip_hide (void);

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,14 @@ typedef enum
META_FRAME_STATUS_CLICKING_MAXIMIZE, META_FRAME_STATUS_CLICKING_MAXIMIZE,
META_FRAME_STATUS_CLICKING_DELETE, META_FRAME_STATUS_CLICKING_DELETE,
META_FRAME_STATUS_CLICKING_MENU, META_FRAME_STATUS_CLICKING_MENU,
META_FRAME_STATUS_RESIZING_SE META_FRAME_STATUS_RESIZING_SE,
META_FRAME_STATUS_RESIZING_S,
META_FRAME_STATUS_RESIZING_SW,
META_FRAME_STATUS_RESIZING_N,
META_FRAME_STATUS_RESIZING_NE,
META_FRAME_STATUS_RESIZING_NW,
META_FRAME_STATUS_RESIZING_W,
META_FRAME_STATUS_RESIZING_E
} MetaFrameStatus; } MetaFrameStatus;
/* This is one widget that manages all the window frames /* This is one widget that manages all the window frames
@ -90,13 +97,18 @@ struct _MetaFrames
GHashTable *frames; GHashTable *frames;
guint tooltip_timeout;
MetaUIFrame *last_motion_frame;
/* The below is all for grabs */ /* The below is all for grabs */
MetaFrameStatus grab_status; MetaFrameStatus grab_status;
MetaUIFrame *grab_frame; MetaUIFrame *grab_frame;
/* initial mouse position for drags */ /* initial mouse position for drags */
int start_root_x, start_root_y; int start_root_x, start_root_y;
/* initial window size or initial window position for drags */ /* initial window position for drags */
int start_window_x, start_window_y; int start_window_x, start_window_y;
/* initial window size for drags */
int start_window_w, start_window_h;
/* button doing the dragging */ /* button doing the dragging */
int start_button; int start_button;
}; };

View File

@ -1,6 +1,6 @@
#! /bin/bash #! /bin/bash
if test -z "$SCREENS"; then if test -z "$SCREENS"; then
SCREENS=2 SCREENS=1
fi fi
if test "$DEBUG" = none; then if test "$DEBUG" = none; then

View File

@ -1,17 +0,0 @@
INCLUDES=@UISLAVE_CFLAGS@ -DHOST_ALIAS=\"@HOST_ALIAS@\"
metacity_uislave_SOURCES = \
fixedtip.h \
fixedtip.c \
main.c \
menu.c \
menu.h \
messages.c \
messages.h \
messagequeue.c \
messagequeue.h
libexec_PROGRAMS=metacity-uislave
metacity_uislave_LDADD = @UISLAVE_LIBS@

View File

@ -1,78 +0,0 @@
/* Metacity fixed tooltip routine */
/*
* 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 "fixedtip.h"
static GtkWidget *tip = NULL;
static GtkWidget *label = NULL;
static gint
expose_handler (GtkTooltips *tooltips)
{
gtk_paint_flat_box (tip->style, tip->window,
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
NULL, tip, "tooltip",
0, 0, -1, -1);
return FALSE;
}
void
meta_fixed_tip_show (int root_x, int root_y,
const char *markup_text)
{
if (tip == NULL)
{
tip = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_set_app_paintable (tip, TRUE);
gtk_window_set_policy (GTK_WINDOW (tip), FALSE, FALSE, TRUE);
gtk_widget_set_name (tip, "gtk-tooltips");
gtk_container_set_border_width (GTK_CONTAINER (tip), 4);
gtk_signal_connect_object (GTK_OBJECT (tip),
"expose_event",
GTK_SIGNAL_FUNC (expose_handler),
NULL);
label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER (tip), label);
gtk_signal_connect (GTK_OBJECT (tip),
"destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&tip);
}
gtk_widget_set_uposition (tip, root_x, root_y);
gtk_label_set_markup (GTK_LABEL (label), markup_text);
gtk_widget_show (tip);
}
void
meta_fixed_tip_hide (void)
{
gtk_widget_destroy (tip);
}

View File

@ -1,32 +0,0 @@
/* Metacity fixed tooltip routine */
/*
* 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_FIXED_TIP_H
#define META_FIXED_TIP_H
#include <gtk/gtk.h>
void meta_fixed_tip_show (int root_x, int root_y,
const char *markup_text);
void meta_fixed_tip_hide (void);
#endif

View File

@ -1,928 +0,0 @@
/* Metacity window frame manager widget */
/*
* 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 "frames.h"
struct _MetaFrame
{
Window xwindow;
GdkWindow *window;
PangoLayout *layout;
MetaFrameFlags flags;
/* w/h of frame window */
int width;
int height;
};
struct _MetaFrameProperties
{
/* Size of left/right/bottom sides */
int left_width;
int right_width;
int bottom_height;
/* Border of blue title region */
GtkBorder title_border;
/* Border inside title region, around title */
GtkBorder text_border;
/* padding on either side of spacer */
int spacer_padding;
/* Size of spacer */
int spacer_width;
int spacer_height;
/* indent of buttons from edges of frame */
int right_inset;
int left_inset;
/* Size of buttons */
int button_width;
int button_height;
/* Space around buttons */
GtkBorder button_border;
/* Space inside button which is clickable but doesn't draw the
* button icon
*/
GtkBorder inner_button_border;
};
typedef struct _MetaFrameGeometry MetaFrameGeometry;
struct _MetaFrameGeometry
{
int left_width;
int right_width;
int top_height;
int bottom_height;
MetaRectangle close_rect;
MetaRectangle max_rect;
MetaRectangle min_rect;
MetaRectangle spacer_rect;
MetaRectangle menu_rect;
MetaRectangle title_rect;
};
static void meta_frames_class_init (MetaFramesClass *klass);
static void meta_frames_init (MetaFrames *frames);
static void meta_frames_destroy (GtkObject *object);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_set (GtkWidget *widget,
GtkStyle *prev_style);
gboolean meta_frames_button_press_event (GtkWidget *widget,
GdkEventButton *event);
gboolean meta_frames_button_release_event (GtkWidget *widget,
GdkEventButton *event);
gboolean meta_frames_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event);
gboolean meta_frames_destroy_event (GtkWidget *widget,
GdkEventAny *event);
gboolean meta_frames_expose_event (GtkWidget *widget,
GdkEventExpose *event);
gboolean meta_frames_key_press_event (GtkWidget *widget,
GdkEventKey *event);
gboolean meta_frames_key_release_event (GtkWidget *widget,
GdkEventKey *event);
gboolean meta_frames_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
gboolean meta_frames_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
gboolean meta_frames_configure_event (GtkWidget *widget,
GdkEventConfigure *event);
gboolean meta_frames_focus_in_event (GtkWidget *widget,
GdkEventFocus *event);
gboolean meta_frames_focus_out_event (GtkWidget *widget,
GdkEventFocus *event);
gboolean meta_frames_map_event (GtkWidget *widget,
GdkEventAny *event);
gboolean meta_frames_unmap_event (GtkWidget *widget,
GdkEventAny *event);
gboolean meta_frames_property_notify_event (GtkWidget *widget,
GdkEventProperty *event);
gboolean meta_frames_client_event (GtkWidget *widget,
GdkEventClient *event);
gboolean meta_frames_window_state_event (GtkWidget *widget,
GdkEventWindowState *event);
static void meta_frames_calc_geometry (MetaFrames *frames,
MetaFrameGeometry *fgeom);
static MetaFrame* meta_frames_lookup_window (MetaFrames *frames,
Window xwindow);
static GtkWidgetClass *parent_class = NULL;
static guint signals[LAST_SIGNAL];
GtkType
meta_frames_get_type (void)
{
static GtkType frames_type = 0;
if (!frames_type)
{
static const GtkTypeInfo frames_info =
{
"MetaFrames",
sizeof (MetaFrames),
sizeof (MetaFramesClass),
(GtkClassInitFunc) meta_frames_class_init,
(GtkObjectInitFunc) meta_frames_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
frames_type = gtk_type_unique (GTK_TYPE_WIDGET, &frames_info);
}
return frames_type;
}
#define BORDER_PROPERTY (name, blurb, docs) \
gtk_widget_class_install_style_property (widget_class, \
g_param_spec_boxed (name, \
blurb, \
docs, \
GTK_TYPE_BORDER, \
G_PARAM_READABLE))
#define INT_PROPERTY (name, default, blurb, docs) \
gtk_widget_class_install_style_property (widget_class, \
g_param_spec_int (name, \
blurb, \
docs, \
0, \
G_MAXINT, \
default, \
G_PARAM_READABLE))
static void
meta_frames_class_init (MetaFramesClass *class)
{
GObjectClass *gobject_class;
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
gobject_class = G_OBJECT_CLASS (class);
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
parent_class = g_type_class_peek_parent (class);
gobject_class->finalize = meta_frames_finalize;
object_class->destroy = meta_frames_destroy;
widget_class->style_set = meta_frames_style_set;
INT_PROPERTY ("left_width", 6, _("Left edge"), _("Left window edge width"));
INT_PROPERTY ("right_width", 6, _("Right edge"), _("Right window edge width"));
INT_PROPERTY ("bottom_height", 7, _("Bottom edge"), _("Bottom window edge height"));
BORDER_PROPERTY ("title_border", _("Title border"), _("Border around title area"));
BORDER_PROPERTY ("text_border", _("Text border"), _("Border around window title text"));
INT_PROPERTY ("spacer_padding", 3, _("Spacer padding"), _("Padding on either side of spacer"));
INT_PROPERTY ("spacer_width", 2, _("Spacer width"), _("Width of spacer"));
INT_PROPERTY ("spacer_height", 10, _("Spacer height"), _("Height of spacer"));
/* same as right_width left_width by default */
INT_PROPERTY ("right_inset", 6, _("Right inset"), _("Distance of buttons from right edge of frame"));
INT_PROPERTY ("left_inset", 6, _("Left inset"), _("Distance of menu button from left edge of frame"));
INT_PROPERTY ("button_width", 14, _("Button width"), _("Width of buttons"));
INT_PROPERTY ("button_height", 14, _("Button height"), _("Height of buttons"));
BORDER_PROPERTY ("button_border", _("Button border"), _("Border around buttons"));
BORDER_PROPERTY ("inner_button_border", _("Inner button border"), _("Border around the icon inside buttons"));
}
static gint
unsigned_long_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const gulong*) v1) == *((const gulong*) v2);
}
static guint
unsigned_long_hash (gconstpointer v)
{
gulong val = * (const gulong *) v;
/* I'm not sure this works so well. */
#if G_SIZEOF_LONG > 4
return (guint) (val ^ (val >> 32));
#else
return val;
#endif
}
static void
meta_frames_init (MetaFrames *frames)
{
GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP;
frames->props = g_new0 (MetaFrameProperties, 1);
frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
}
static void
meta_frames_destroy (GtkObject *object)
{
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
listify_func (gpointer key, gpointer value, gpointer data)
{
GSList **listp;
listp = data;
*listp = g_slist_prepend (*listp, value);
}
static void
meta_frames_finalize (GObject *object)
{
MetaFrames *frames;
GSList *winlist;
GSList *tmp;
frames = META_FRAMES (object);
winlist = NULL;
g_hash_table_foreach (frames->frames,
listify_func,
&winlist);
/* Unmanage all frames */
tmp = winlist;
while (tmp != NULL)
{
MetaFrame *frame;
frame = tmp->data;
meta_frames_unmanage_window (frames, frame->xwindow);
tmp = tmp->next;
}
g_slist_free (winlist);
g_assert (g_hash_table_size (frames->frames) == 0);
g_hash_table_destroy (frames->frames);
g_free (frames->props);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
meta_frames_style_set (GtkWidget *widget,
GtkStyle *prev_style)
{
MetaFrames *frames;
/* left, right, top, bottom */
static GtkBorder default_title_border = { 3, 4, 4, 3 };
static GtkBorder default_text_border = { 2, 2, 2, 2 };
static GtkBorder default_button_border = { 1, 1, 1, 1 };
static GtkBorder default_inner_button_border = { 3, 3, 3, 3 };
GtkBorder *title_border;
GtkBorder *text_border;
GtkBorder *button_border;
GtkBorder *inner_button_border;
MetaFrameProperties props;
frames = META_FRAMES (widget);
gtk_widget_style_get (widget,
"left_width",
&props.left_width,
"right_width",
&props.right_width,
"bottom_height",
&props.bottom_height,
"title_border",
&title_border,
"text_border",
&text_border,
"spacer_padding",
&props.spacer_padding,
"spacer_width",
&props.spacer_width,
"spacer_height",
&props.spacer_height,
"right_inset",
&props.right_inset,
"left_inset",
&props.left_inset,
"button_width",
&props.button_width,
"button_height",
&props.button_height,
"button_border",
&button_border,
"inner_button_border",
&inner_button_border,
NULL);
if (title_border)
props.title_border = *title_border;
else
props.title_border = default_title_border;
g_free (title_border);
if (text_border)
props.text_border = *text_border;
else
props.text_border = default_text_border;
g_free (text_border);
if (button_border)
props.button_border = *button_border;
else
props.button_border = default_button_border;
g_free (button_border);
if (inner_button_border)
props.inner_button_border = *inner_button_border;
else
props.inner_button_border = default_inner_button_border;
g_free (inner_button_border);
*(frames->props) = props;
{
PangoFontMetrics metrics;
PangoFont *font;
gchar *lang;
font = pango_context_load_font (gtk_widget_get_pango_context (widget),
widget->style->font_desc);
lang = pango_context_get_lang (gtk_widget_get_pango_context (widget));
pango_font_get_metrics (font, lang, &metrics);
g_free (lang);
g_object_unref (G_OBJECT (font));
frames->text_height = metrics.ascent + metrics.descent;
}
}
static void
meta_frames_calc_geometry (MetaFrames *frames,
MetaFrame *frame,
MetaFrameGeometry *fgeom)
{
int x;
int button_y;
int title_right_edge;
gboolean shaded;
MetaFrameProperties props;
int buttons_height, title_height, spacer_height;
props = *(frames->props);
buttons_height = props.button_height +
props.button_border.top + props.button_border.bottom;
title_height = frames->text_height +
props.text_border.top + props.text_border.bottom +
props.title_border.top + props.title_border.bottom;
spacer_height = props.spacer_height;
fgeom->top_height = MAX (buttons_height, title_height);
fgeom->top_height = MAX (fgeom->top_height, spacer_height);
fgeom->left_width = props.left_width;
fgeom->right_width = props.right_width;
if (frame->flags & META_FRAME_SHADED)
fgeom->bottom_height = 0;
else
fgeom->bottom_height = props.bottom_height;
x = frame->width - fgeom->button_inset;
/* center buttons */
button_y = (fgeom->top_height -
(props.button_height + props.button_border.top + props.button_border.bottom)) / 2 + props.button_border.top;
if ((frame->flags & META_FRAME_ALLOWS_DELETE) &&
x >= 0)
{
fgeom->close_rect.x = x - props.button_border.right - props.button_width;
fgeom->close_rect.y = button_y;
fgeom->close_rect.width = props.button_width;
fgeom->close_rect.height = props.button_height;
x = fgeom->close_rect.x - props.button_border.left;
}
else
{
fgeom->close_rect.x = 0;
fgeom->close_rect.y = 0;
fgeom->close_rect.width = 0;
fgeom->close_rect.height = 0;
}
if ((frame->flags & META_FRAME_ALLOWS_MAXIMIZE) &&
x >= 0)
{
fgeom->max_rect.x = x - props.button_border.right - props.button_width;
fgeom->max_rect.y = button_y;
fgeom->max_rect.width = props.button_width;
fgeom->max_rect.height = props.button_height;
x = fgeom->max_rect.x - props.button_border.left;
}
else
{
fgeom->max_rect.x = 0;
fgeom->max_rect.y = 0;
fgeom->max_rect.width = 0;
fgeom->max_rect.height = 0;
}
if ((frame->flags & META_FRAME_ALLOWS_MINIMIZE) &&
x >= 0)
{
fgeom->min_rect.x = x - props.button_border.right - props.button_width;
fgeom->min_rect.y = button_y;
fgeom->min_rect.width = props.button_width;
fgeom->min_rect.height = props.button_height;
x = fgeom->min_rect.x - props.button_border.left;
}
else
{
fgeom->min_rect.x = 0;
fgeom->min_rect.y = 0;
fgeom->min_rect.width = 0;
fgeom->min_rect.height = 0;
}
if ((fgeom->close_rect.width > 0 ||
fgeom->max_rect.width > 0 ||
fgeom->min_rect.width > 0) &&
x >= 0)
{
fgeom->spacer_rect.x = x - props.spacer_padding - props.spacer_width;
fgeom->spacer_rect.y = (fgeom->top_height - props.spacer_height) / 2;
fgeom->spacer_rect.width = props.spacer_width;
fgeom->spacer_rect.height = props.spacer_height;
x = fgeom->spacer_rect.x - props.spacer_padding;
}
else
{
fgeom->spacer_rect.x = 0;
fgeom->spacer_rect.y = 0;
fgeom->spacer_rect.width = 0;
fgeom->spacer_rect.height = 0;
}
title_right_edge = x - props.title_border.right;
/* Now x changes to be position from the left */
x = fgeom->left_inset;
if ((frame->flags & META_FRAME_ALLOWS_MENU) &&
x < title_right_edge)
{
fgeom->menu_rect.x = x + props.button_border.left;
fgeom->menu_rect.y = button_y;
fgeom->menu_rect.width = props.button_width;
fgeom->menu_rect.height = props.button_height;
x = fgeom->menu_rect.x + fgeom->menu_rect.width + props.button_border.right;
}
else
{
fgeom->menu_rect.x = 0;
fgeom->menu_rect.y = 0;
fgeom->menu_rect.width = 0;
fgeom->menu_rect.height = 0;
}
/* If menu overlaps close button, then the menu wins since it
* lets you perform any operation including close
*/
if (fgeom->close_rect.width > 0 &&
fgeom->close_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
{
fgeom->close_rect.width = 0;
fgeom->close_rect.height = 0;
}
/* We always fill as much vertical space as possible with title rect,
* rather than centering it like the buttons and spacer
*/
fgeom->title_rect.x = x + props.title_border.left;
fgeom->title_rect.y = props.title_border.top;
fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
fgeom->title_rect.height = frames->top_height - props.title_border.top - props.title_border.bottom;
/* Nuke title if it won't fit */
if (fgeom->title_rect.width < 0 ||
fgeom->title_rect.height < 0)
{
fgeom->title_rect.width = 0;
fgeom->title_rect.height = 0;
}
}
void
meta_frames_manage_window (MetaFrames *frames,
Window xwindow)
{
MetaFrame *frame;
g_return_if_fail (GDK_IS_WINDOW (window));
frame = g_new (MetaFrame, 1);
gdk_error_trap_push ();
frame->window = gdk_window_foreign_new (xwindow);
if (frame->window == NULL)
{
gdk_flush ();
gdk_error_trap_pop ();
g_free (frame);
meta_ui_warning ("Frame 0x%lx disappeared as we managed it\n", xwindow);
return;
}
gdk_window_set_user_data (frame->window, frames);
gdk_window_set_events (frame->window,
GDK_EXPOSURE_MASK |
GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_STRUCTURE_MASK);
gdk_drawable_get_size (GDK_DRAWABLE (frame->window),
&frame->width, &frame->height);
XGrabButton (gdk_display, AnyButton, AnyModifier,
xwindow, False,
ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | PointerMotionHintMask,
GrabModeAsync, GrabModeAsync,
False, None);
gdk_flush ();
if (gdk_error_trap_pop ())
{
g_object_unref (G_OBJECT (frame->window));
g_free (frame);
meta_ui_warning ("Errors managing frame 0x%lx\n", xwindow);
return;
}
frame->xwindow = xwindow;
frame->layout = NULL;
frame->flags = 0;
g_hash_table_insert (frames->frames, &frame->xwindow);
}
void
meta_frames_unmanage_window (MetaFrames *frames,
Window xwindow)
{
MetaFrame *frame;
frame = g_hash_table_lookup (frames->frames, &xwindow);
if (frame)
{
g_hash_table_remove (frames->frames, &frame->xwindow);
g_object_unref (G_OBJECT (frame->window));
if (frame->layout)
g_object_unref (G_OBJECT (frame->layout));
g_free (frame);
}
else
meta_ui_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
}
static MetaFrame*
meta_frames_lookup_window (MetaFrames *frames,
Window xwindow)
{
MetaFrame *frame;
frame = g_hash_table_lookup (frames->frames, &xwindow);
return frame;
}
gboolean
meta_frames_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_button_release_event (GtkWidget *widget,
GdkEventButton *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_destroy_event (GtkWidget *widget,
GdkEventAny *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_expose_event (GtkWidget *widget,
GdkEventExpose *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_key_release_event (GtkWidget *widget,
GdkEventKey *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_configure_event (GtkWidget *widget,
GdkEventConfigure *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_focus_in_event (GtkWidget *widget,
GdkEventFocus *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_focus_out_event (GtkWidget *widget,
GdkEventFocus *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_map_event (GtkWidget *widget,
GdkEventAny *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_unmap_event (GtkWidget *widget,
GdkEventAny *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_property_notify_event (GtkWidget *widget,
GdkEventProperty *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_client_event (GtkWidget *widget,
GdkEventClient *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}
gboolean
meta_frames_window_state_event (GtkWidget *widget,
GdkEventWindowState *event)
{
MetaFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (widget);
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
if (frame == NULL)
return FALSE;
return TRUE;
}

View File

@ -1,77 +0,0 @@
/* Metacity window frame manager widget */
/*
* 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_FRAMES_H
#define META_FRAMES_H
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "messages.h"
/* This is one widget that manages all the window frames
* as subwindows.
*/
#define META_TYPE_FRAMES (meta_frames_get_type ())
#define META_FRAMES(obj) (META_CHECK_CAST ((obj), META_TYPE_FRAMES, MetaFrames))
#define META_FRAMES_CLASS(klass) (META_CHECK_CLASS_CAST ((klass), META_TYPE_FRAMES, MetaFramesClass))
#define META_IS_FRAMES(obj) (META_CHECK_TYPE ((obj), META_TYPE_FRAMES))
#define META_IS_FRAMES_CLASS(klass) (META_CHECK_CLASS_TYPE ((klass), META_TYPE_FRAMES))
#define META_FRAMES_GET_CLASS(obj) (META_CHECK_GET_CLASS ((obj), META_TYPE_FRAMES, MetaFramesClass))
typedef struct _MetaFrames MetaFrames;
typedef struct _MetaFramesClass MetaFramesClass;
typedef struct _MetaFrame MetaFrame;
typedef struct _MetaFrameProperties MetaFrameProperties;
struct _MetaFrames
{
GtkWindow parent_instance;
/* If we did a widget per frame, we wouldn't want to cache this. */
MetaFrameProperties *props;
int text_height;
GHashTable *frames;
};
struct _MetaFramesClass
{
GtkWindowClass parent_class;
};
GType meta_frames_get_type (void) G_GNUC_CONST;
MetaFrames *meta_frames_new (void);
void meta_frames_manage_window (MetaFrames *frames,
Window xwindow);
void meta_frames_unmanage_window (MetaFrames *frames,
Window xwindow);
void meta_frames_set_title (MetaFrames *frames,
Window xwindow,
const char *title);
#endif

View File

@ -1,142 +0,0 @@
/* Metacity UI slave main() */
/*
* 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 "messagequeue.h"
#include "fixedtip.h"
#include "main.h"
#include "menu.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <gtk/gtk.h>
static void message_callback (MetaMessageQueue *mq,
MetaMessage *message,
gpointer data);
int
main (int argc, char **argv)
{
MetaMessageQueue *mq;
/* report our nature to the window manager */
meta_message_send_check ();
gtk_init (&argc, &argv);
mq = meta_message_queue_new (0, message_callback, NULL);
gtk_main ();
return 0;
}
static void
message_callback (MetaMessageQueue *mq,
MetaMessage *message,
gpointer data)
{
switch (message->header.message_code)
{
case MetaMessageShowTipCode:
meta_fixed_tip_show (message->show_tip.root_x,
message->show_tip.root_y,
message->show_tip.markup);
break;
case MetaMessageHideTipCode:
meta_fixed_tip_hide ();
break;
case MetaMessageShowWindowMenuCode:
meta_window_menu_show (message->show_menu.window,
message->show_menu.root_x,
message->show_menu.root_y,
message->show_menu.button,
message->show_menu.ops,
message->show_menu.insensitive,
message->show_menu.timestamp);
break;
case MetaMessageHideWindowMenuCode:
meta_window_menu_hide ();
break;
default:
meta_ui_warning ("Unhandled message code %d\n",
message->header.message_code);
break;
}
}
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);
fflush (stderr); /* though stderr is unbuffered right */
g_free (str);
}
#if 0
{
int i;
/* Try breaking message queue system. */
i = 0;
while (i < 1500)
{
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

View File

@ -1,32 +0,0 @@
/* Metacity UI slave main() */
/*
* 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_MAIN_H
#define META_UI_MAIN_H
void meta_ui_warning (const char *format, ...);
/* FIXME */
#define _(x) x
#define N_(x) x
#endif

View File

@ -1,486 +0,0 @@
/* Metacity window menu */
/*
* 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 "menu.h"
#include "main.h"
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
typedef struct _MenuItem MenuItem;
typedef struct _MenuData MenuData;
struct _MenuItem
{
MetaMessageWindowMenuOps op;
const char *stock_id;
const char *label;
};
struct _MenuData
{
GdkWindow *window;
MetaMessageWindowMenuOps op;
};
static void activate_cb (GtkWidget *menuitem, gpointer data);
static GtkWidget *menu = NULL;
static MenuItem menuitems[] = {
{ META_MESSAGE_MENU_DELETE, GTK_STOCK_CLOSE, N_("_Close") },
{ META_MESSAGE_MENU_MINIMIZE, NULL, N_("_Minimize") },
{ META_MESSAGE_MENU_MAXIMIZE, NULL, N_("Ma_ximize") },
{ META_MESSAGE_MENU_UNMAXIMIZE, NULL, N_("_Unmaximize") },
{ META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") },
{ META_MESSAGE_MENU_UNSHADE, NULL, N_("U_nshade") },
{ 0, NULL, NULL }, /* separator */
{ META_MESSAGE_MENU_STICK, NULL, N_("Put on _All Workspaces") },
{ META_MESSAGE_MENU_UNSTICK, NULL, N_("Only on _This Workspace") }
};
static void
popup_position_func (GtkMenu *menu,
gint *x,
gint *y,
gboolean *push_in,
gpointer user_data)
{
GtkRequisition req;
GdkPoint *pos;
pos = user_data;
gtk_widget_size_request (GTK_WIDGET (menu), &req);
*x = pos->x;
*y = pos->y;
/* Ensure onscreen */
*x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
}
static gint
get_num_desktops (void)
{
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
gulong *num;
int result;
XGetWindowProperty (gdk_display, gdk_root_window,
gdk_atom_intern ("_NET_NUMBER_OF_DESKTOPS", FALSE),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, (guchar **)&num);
if (type != XA_CARDINAL)
return 0;
result = *num;
XFree (num);
return result;
}
static gint
get_active_desktop (void)
{
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
gulong *num;
int result;
XGetWindowProperty (gdk_display, gdk_root_window,
gdk_atom_intern ("_NET_CURRENT_DESKTOP", FALSE),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, (guchar **)&num);
if (type != XA_CARDINAL)
return 0;
result = *num;
XFree (num);
return result;
}
static gulong
get_current_desktop (GdkWindow *window)
{
Atom type;
gint format;
gulong nitems;
gulong bytes_after;
gulong *num;
gulong result;
int err;
gdk_error_trap_push ();
type = None;
XGetWindowProperty (gdk_display, GDK_WINDOW_XID (window),
gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
0, G_MAXLONG,
False, XA_CARDINAL, &type, &format, &nitems,
&bytes_after, (guchar **)&num);
err = gdk_error_trap_pop ();
if (err != Success)
meta_ui_warning ("Error %d getting _NET_WM_DESKTOP\n", err);
if (type != XA_CARDINAL)
{
meta_ui_warning ("_NET_WM_DESKTOP has wrong type %s\n", gdk_atom_name (type));
return 0xFFFFFFFF; /* sticky */
}
result = *num;
XFree (num);
return result;
}
void
meta_window_menu_show (gulong xwindow,
int root_x, int root_y,
int button,
MetaMessageWindowMenuOps ops,
MetaMessageWindowMenuOps insensitive,
guint32 timestamp)
{
int i;
GdkWindow *window;
GdkPoint *pt;
int n_workspaces;
int current_workspace;
if (menu)
gtk_widget_destroy (menu);
window = gdk_xid_table_lookup (xwindow);
if (window)
g_object_ref (G_OBJECT (window));
else
window = gdk_window_foreign_new (xwindow);
/* X error creating the foreign window means NULL here */
if (window == NULL)
return;
menu = gtk_menu_new ();
i = 0;
while (i < G_N_ELEMENTS (menuitems))
{
if (ops & menuitems[i].op || menuitems[i].op == 0)
{
GtkWidget *mi;
MenuData *md;
if (menuitems[i].op == 0)
{
mi = gtk_separator_menu_item_new ();
}
else
{
if (menuitems[i].stock_id)
{
GtkWidget *image;
mi = gtk_image_menu_item_new_with_mnemonic (menuitems[i].label);
image = gtk_image_new_from_stock (menuitems[i].stock_id,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi),
image);
gtk_widget_show (image);
}
else
{
mi = gtk_menu_item_new_with_mnemonic (menuitems[i].label);
}
if (insensitive & menuitems[i].op)
gtk_widget_set_sensitive (mi, FALSE);
md = g_new (MenuData, 1);
md->window = window;
md->op = menuitems[i].op;
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (activate_cb),
md);
}
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
mi);
gtk_widget_show (mi);
}
++i;
}
if (ops & META_MESSAGE_MENU_WORKSPACES)
{
n_workspaces = get_num_desktops ();
current_workspace = get_current_desktop (window);
meta_ui_warning ("Creating %d workspace menu current %d\n",
n_workspaces, current_workspace);
if (n_workspaces > 0)
{
GtkWidget *mi;
i = 0;
while (i < n_workspaces)
{
char *label;
MenuData *md;
if (current_workspace == 0xFFFFFFFF)
label = g_strdup_printf (_("Only on workspace _%d\n"),
i + 1);
else
label = g_strdup_printf (_("Move to workspace _%d\n"),
i + 1);
mi = gtk_menu_item_new_with_mnemonic (label);
g_free (label);
if (current_workspace == i ||
insensitive & META_MESSAGE_MENU_WORKSPACES)
gtk_widget_set_sensitive (mi, FALSE);
md = g_new (MenuData, 1);
md->window = window;
md->op = META_MESSAGE_MENU_WORKSPACES;
g_object_set_data (G_OBJECT (mi),
"workspace",
GINT_TO_POINTER (i));
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (activate_cb),
md);
gtk_menu_shell_append (GTK_MENU_SHELL (menu),
mi);
gtk_widget_show (mi);
++i;
}
}
}
else
meta_ui_warning ("not creating workspace menu\n");
gtk_signal_connect (GTK_OBJECT (menu),
"destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&menu);
pt = g_new (GdkPoint, 1);
g_object_set_data_full (G_OBJECT (menu),
"destroy-point",
pt,
g_free);
pt->x = root_x;
pt->y = root_y;
gtk_menu_popup (GTK_MENU (menu),
NULL, NULL,
popup_position_func, pt,
button,
timestamp);
if (!GTK_MENU_SHELL (menu)->have_xgrab)
meta_ui_warning ("GtkMenu failed to grab the pointer\n");
}
void
meta_window_menu_hide (void)
{
if (menu)
gtk_widget_destroy (menu);
}
static void
close_window (GdkWindow *window)
{
XClientMessageEvent ev;
ev.type = ClientMessage;
ev.window = GDK_WINDOW_XID (window);
ev.message_type = gdk_atom_intern ("_NET_CLOSE_WINDOW", FALSE);
ev.format = 32;
ev.data.l[0] = 0;
ev.data.l[1] = 0;
gdk_error_trap_push ();
XSendEvent (gdk_display,
gdk_root_window, False,
SubstructureNotifyMask | SubstructureRedirectMask,
(XEvent*) &ev);
gdk_flush ();
gdk_error_trap_pop ();
}
static void
wmspec_change_state (gboolean add,
GdkWindow *window,
GdkAtom state1,
GdkAtom state2)
{
XEvent xev;
gulong op;
if (add)
op = _NET_WM_STATE_ADD;
else
op = _NET_WM_STATE_REMOVE;
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.display = gdk_display;
xev.xclient.window = GDK_WINDOW_XID (window);
xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
xev.xclient.format = 32;
xev.xclient.data.l[0] = op;
xev.xclient.data.l[1] = state1;
xev.xclient.data.l[2] = state2;
XSendEvent (gdk_display, gdk_root_window, False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
static void
wmspec_change_desktop (GdkWindow *window,
gint desktop)
{
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.display = gdk_display;
xev.xclient.window = GDK_WINDOW_XID (window);
xev.xclient.message_type = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
xev.xclient.format = 32;
xev.xclient.data.l[0] = desktop;
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = 0;
XSendEvent (gdk_display, gdk_root_window, False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
static void
activate_cb (GtkWidget *menuitem, gpointer data)
{
MenuData *md;
md = data;
switch (md->op)
{
case META_MESSAGE_MENU_DELETE:
close_window (md->window);
break;
case META_MESSAGE_MENU_MINIMIZE:
gdk_window_iconify (md->window);
break;
case META_MESSAGE_MENU_UNMAXIMIZE:
wmspec_change_state (FALSE, md->window,
gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE),
gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE));
break;
case META_MESSAGE_MENU_MAXIMIZE:
wmspec_change_state (TRUE, md->window,
gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE),
gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE));
break;
case META_MESSAGE_MENU_UNSHADE:
wmspec_change_state (FALSE, md->window,
gdk_atom_intern ("_NET_WM_STATE_SHADED", FALSE),
0);
break;
case META_MESSAGE_MENU_SHADE:
wmspec_change_state (TRUE, md->window,
gdk_atom_intern ("_NET_WM_STATE_SHADED", FALSE),
0);
break;
case META_MESSAGE_MENU_WORKSPACES:
{
int workspace;
workspace = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
"workspace"));
wmspec_change_desktop (md->window, workspace);
}
break;
case META_MESSAGE_MENU_STICK:
wmspec_change_desktop (md->window, 0xFFFFFFFF);
break;
case META_MESSAGE_MENU_UNSTICK:
wmspec_change_desktop (md->window, get_active_desktop ());
break;
default:
meta_ui_warning (G_STRLOC": Unknown window op\n");
break;
}
if (menu)
gtk_widget_destroy (menu);
g_object_unref (G_OBJECT (md->window));
g_free (md);
}

View File

@ -1,39 +0,0 @@
/* Metacity window menu */
/*
* 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_MENU_H
#define META_MENU_H
#include <gtk/gtk.h>
#include "messages.h"
void meta_window_menu_show (gulong xwindow,
int root_x,
int root_y,
int button,
MetaMessageWindowMenuOps ops,
MetaMessageWindowMenuOps insensitive,
guint32 timestamp);
void meta_window_menu_hide (void);
#endif

View File

@ -1,564 +0,0 @@
/* Metacity IPC message source for main loop */
/*
* 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 "messagequeue.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#ifdef METACITY_COMPILE
#include "util.h"
#else
#include "main.h"
void
meta_debug_spew (const char *format, ...)
{
}
void
meta_verbose (const char *format, ...)
{
}
void
meta_bug (const char *format, ...)
{
/* stop us in a debugger */
abort ();
}
void
meta_warning (const char *format, ...)
{
}
void
meta_fatal (const char *format, ...)
{
exit (1);
}
#endif /* !METACITY_COMPILE */
typedef enum
{
READ_FAILED = 0, /* FALSE */
READ_OK,
READ_EOF
} ReadResult;
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
};
struct _MetaMessageQueue
{
GSource source;
GPollFD out_poll;
GQueue *queue;
GString *buf;
GString *current_message;
int current_required_len;
int last_serial;
};
MetaMessageQueue*
meta_message_queue_new (int fd,
MetaMessageQueueFunc func,
gpointer data)
{
MetaMessageQueue *mq;
GSource *source;
source = g_source_new (&mq_funcs, sizeof (MetaMessageQueue));
mq = (MetaMessageQueue*) source;
mq->queue = g_queue_new ();
mq->buf = g_string_new ("");
mq->current_message = g_string_new ("");
mq->current_required_len = 0;
mq->last_serial = 0;
mq->out_poll.fd = fd;
mq->out_poll.events = G_IO_IN;
g_source_add_poll (source, &mq->out_poll);
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 mq;
}
void
meta_message_queue_free (MetaMessageQueue *mq)
{
GSource *source;
source = (GSource*) mq;
g_source_destroy (source);
}
static void
append_pending (MetaMessageQueue *mq)
{
int needed;
needed = mq->current_required_len - mq->current_message->len;
g_assert (needed >= 0);
needed = MIN (needed, mq->buf->len);
/* Move data from buf to current_message */
if (needed > 0)
{
meta_verbose ("Moving %d bytes from buffer to current incomplete message\n",
needed);
g_string_append_len (mq->current_message,
mq->buf->str,
needed);
g_string_erase (mq->buf,
0, needed);
}
g_assert (mq->current_message->len <= mq->current_required_len);
if (mq->current_required_len > 0 &&
mq->current_message->len == mq->current_required_len)
{
MetaMessage *message;
MetaMessageFooter *footer;
message = g_new (MetaMessage, 1);
memcpy (message,
mq->current_message->str, mq->current_message->len);
if (message->header.length != mq->current_required_len)
meta_bug ("Message length changed?\n");
if (message->header.serial != mq->last_serial)
meta_bug ("Message serial changed?\n");
footer = META_MESSAGE_FOOTER (message);
if (footer->checksum == META_MESSAGE_CHECKSUM (message))
{
g_queue_push_tail (mq->queue, message);
meta_verbose ("Added %d-byte message serial %d to queue\n",
mq->current_message->len, message->header.serial);
}
else
{
meta_bug ("Bad checksum %d on %d-byte message from UI slave\n",
footer->checksum, mq->current_message->len);
}
mq->current_required_len = 0;
g_string_truncate (mq->current_message, 0);
}
else if (mq->current_required_len > 0)
{
meta_verbose ("Storing %d bytes of incomplete message\n",
mq->current_message->len);
}
}
static void
mq_queue_messages (MetaMessageQueue *mq)
{
while (mq->buf->len > 0)
{
if (mq->current_required_len > 0)
{
/* We had a pending message. */
append_pending (mq);
}
else if (mq->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;
g_assert (mq->current_required_len == 0);
g_assert (mq->current_message->len == 0);
meta_verbose ("Scanning for escape sequence in %d bytes\n",
mq->buf->len);
/* note that the data from the UI slave includes the nul byte */
esc = META_MESSAGE_ESCAPE;
esc_pos = -1;
p = mq->buf->str;
while (p != (mq->buf->str + mq->buf->len))
{
if (*p == *esc)
{
esc_pos = 0;
while (*p == esc[esc_pos])
{
++esc_pos;
++p;
if (esc_pos == META_MESSAGE_ESCAPE_LEN ||
p == (mq->buf->str + mq->buf->len))
goto out;
}
esc_pos = -1;
}
else
{
++p;
}
}
out:
if (esc_pos == META_MESSAGE_ESCAPE_LEN)
{
/* We found an entire escape sequence; can safely toss
* out the entire buffer before it
*/
int ignored;
g_assert (esc[META_MESSAGE_ESCAPE_LEN-1] == *(p-1));
ignored = p - mq->buf->str;
ignored -= META_MESSAGE_ESCAPE_LEN;
g_assert (ignored >= 0);
g_assert (mq->buf->str[ignored] == esc[0]);
if (ignored > 0)
{
g_string_erase (mq->buf, 0, ignored);
meta_verbose ("Ignoring %d bytes before escape, new buffer len %d\n",
ignored, mq->buf->len);
}
else
{
g_assert (p == (mq->buf->str + META_MESSAGE_ESCAPE_LEN));
}
}
else if (esc_pos < 0)
{
/* End of buffer doesn't begin an escape sequence;
* toss out entire buffer.
*/
meta_verbose ("Emptying %d-byte buffer not containing escape sequence\n",
mq->buf->len);
g_string_truncate (mq->buf, 0);
goto need_more_data;
}
else
{
meta_verbose ("Buffer ends with partial escape sequence\n");
goto need_more_data;
}
g_assert (strcmp (mq->buf->str, META_MESSAGE_ESCAPE) == 0);
if (mq->buf->len < (META_MESSAGE_ESCAPE_LEN + sizeof (MetaMessageHeader)))
{
meta_verbose ("Buffer has full escape sequence but lacks header\n");
goto need_more_data;
}
g_string_erase (mq->buf, 0, META_MESSAGE_ESCAPE_LEN);
meta_verbose ("Stripped escape off front of buffer, new buffer len %d\n",
mq->buf->len);
g_assert (mq->buf->len >= sizeof (MetaMessageHeader));
memcpy (&header, mq->buf->str, sizeof (MetaMessageHeader));
/* Length includes the header even though it's in the header. */
meta_verbose ("Read header, code: %d length: %d serial: %d\n",
header.message_code, header.length, header.serial);
if (header.serial != mq->last_serial + 1)
meta_bug ("Wrong message serial number %d from UI slave!\n", header.serial);
mq->last_serial = header.serial;
mq->current_required_len = header.length;
append_pending (mq);
}
else
goto need_more_data;
}
need_more_data:
return;
}
static gboolean
mq_messages_pending (MetaMessageQueue *mq)
{
return mq->queue->length > 0;
/* these are useless until we wake up on poll again */
#if 0
mq->buf->len > 0 ||
mq->current_message->len > 0;
#endif
}
static gboolean
mq_prepare (GSource *source, gint *timeout)
{
MetaMessageQueue *mq;
mq = (MetaMessageQueue*) source;
*timeout = -1;
mq_queue_messages (mq);
return mq_messages_pending (mq);
}
static gboolean
mq_check (GSource *source)
{
MetaMessageQueue *mq;
mq = (MetaMessageQueue*) source;
mq_queue_messages (mq);
if (mq->out_poll.revents & G_IO_IN)
{
ReadResult res;
res = read_data (mq->buf, mq->out_poll.fd);
switch (res)
{
case READ_OK:
meta_verbose ("Read data from slave, %d bytes in buffer\n",
mq->buf->len);
break;
case READ_EOF:
#ifdef METACITY_COMPILE
meta_verbose ("EOF reading stdout from slave process\n");
#else
meta_ui_warning ("Metacity parent process disappeared\n");
exit (1);
#endif
break;
case READ_FAILED:
/* read_data printed the error */
break;
}
}
if (mq->out_poll.revents & G_IO_HUP)
{
#ifdef METACITY_COMPILE
meta_verbose ("UI slave hung up\n");
#else
meta_ui_warning ("Metacity parent process hung up\n");
exit (1);
#endif
}
mq->out_poll.revents = 0;
return mq_messages_pending (mq);
}
static gboolean
mq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
{
MetaMessageQueue *mq;
mq = (MetaMessageQueue*) source;
if (mq->queue->length > 0)
{
MetaMessageQueueFunc func;
MetaMessage *msg;
static int count = 0;
++count;
msg = g_queue_pop_head (mq->queue);
func = (MetaMessageQueueFunc) callback;
(* func) (mq, msg, user_data);
meta_verbose ("%d messages dispatched\n", count);
g_free (msg);
}
return TRUE;
}
static void
mq_destroy (GSource *source)
{
MetaMessageQueue *mq;
mq = (MetaMessageQueue*) source;
while (mq->queue->length > 0)
{
MetaMessage *msg;
msg = g_queue_pop_head (mq->queue);
g_free (msg);
}
g_string_free (mq->buf, TRUE);
g_string_free (mq->current_message, TRUE);
g_queue_free (mq->queue);
/* source itself is freed by glib */
}
static ReadResult
read_data (GString *str,
gint fd)
{
#define BUFSIZE 1024
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;
}
/* Wait forever and build infinite queue until we get
* the desired serial_of_request or one higher than it
*/
void
meta_message_queue_wait_for_reply (MetaMessageQueue *mq,
int serial_of_request)
{
ReadResult res;
int prev_len;
prev_len = 0;
while (TRUE)
{
if (prev_len < mq->queue->length)
{
GList *tmp;
tmp = g_list_nth (mq->queue->head, prev_len);
while (tmp != NULL)
{
MetaMessage *msg = tmp->data;
if (msg->header.request_serial == serial_of_request)
return;
if (msg->header.request_serial > serial_of_request)
{
meta_warning ("Serial request %d is greater than the awaited request %d\n",
msg->header.request_serial, serial_of_request);
return;
}
tmp = tmp->next;
}
prev_len = mq->queue->length;
}
res = read_data (mq->buf, mq->out_poll.fd);
switch (res)
{
case READ_OK:
meta_verbose ("Read data from slave, %d bytes in buffer\n",
mq->buf->len);
break;
case READ_EOF:
#ifdef METACITY_COMPILE
meta_verbose ("EOF reading stdout from slave process\n");
#else
meta_ui_warning ("Metacity parent process disappeared\n");
exit (1);
#endif
return;
break;
case READ_FAILED:
/* read_data printed the error */
return;
break;
}
mq_queue_messages (mq);
}
}

View File

@ -1,47 +0,0 @@
/* Metacity IPC message source for main loop */
/*
* 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_MESSAGE_QUEUE_H
#define META_MESSAGE_QUEUE_H
#include <glib.h>
#ifdef METACITY_COMPILE
#include "uislave/messages.h"
#else
#include "messages.h"
#endif
typedef struct _MetaMessageQueue MetaMessageQueue;
typedef void (* MetaMessageQueueFunc) (MetaMessageQueue *mq,
MetaMessage *message,
gpointer data);
MetaMessageQueue* meta_message_queue_new (int fd,
MetaMessageQueueFunc func,
gpointer data);
void meta_message_queue_free (MetaMessageQueue *mq);
void meta_message_queue_wait_for_reply (MetaMessageQueue *mq,
int serial_of_request);
#endif

View File

@ -1,173 +0,0 @@
/* 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 <ctype.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,
int request_serial);
void
meta_message_send_check (void)
{
MetaMessageCheck check;
memset (&check, 0, META_MESSAGE_LENGTH (MetaMessageCheck));
check.header.message_code = MetaMessageCheckCode;
check.header.length = META_MESSAGE_LENGTH (MetaMessageCheck);
strncpy (check.metacity_version, VERSION, META_MESSAGE_MAX_VERSION_LEN);
check.metacity_version[META_MESSAGE_MAX_VERSION_LEN] = '\0';
strncpy (check.host_alias, HOST_ALIAS, META_MESSAGE_MAX_HOST_ALIAS_LEN);
check.host_alias[META_MESSAGE_MAX_HOST_ALIAS_LEN] = '\0';
check.messages_version = META_MESSAGES_VERSION;
send_message ((MetaMessage*)&check, 0);
}
static int
write_bytes (void *buf, int bytes)
{
const char *p;
int left;
left = bytes;
p = (char*) buf;
while (left > 0)
{
int written;
written = write (1, p, left);
if (written < 0)
return -1;
left -= written;
p += written;
}
g_assert (p == ((char*)buf) + bytes);
return 0;
}
#if 0
static void
print_mem (int fd, void *mem, int len)
{
char *p = (char*) mem;
int i;
char unknown = 'Z';
char null = 'n';
i = 0;
while (i < len)
{
if (p[i] == '\0')
write (fd, &null, 1);
else if (isascii (p[i]))
write (fd, p + i, 1);
else
write (fd, &unknown, 1);
++i;
}
}
#endif
static void
send_message (MetaMessage *message,
int request_serial)
{
static int serial = 1;
MetaMessageFooter *footer;
message->header.serial = serial;
message->header.request_serial = request_serial;
footer = META_MESSAGE_FOOTER (message);
footer->checksum = META_MESSAGE_CHECKSUM (message);
++serial;
#if 0
meta_ui_warning ("'");
print_mem (2, message, message->header.length);
meta_ui_warning ("'\n");
#endif
if (write_bytes (META_MESSAGE_ESCAPE, META_MESSAGE_ESCAPE_LEN) < 0)
meta_ui_warning ("Failed to write escape sequence: %s\n",
g_strerror (errno));
if (write_bytes (message, message->header.length) < 0)
meta_ui_warning ("Failed to write message: %s\n",
g_strerror (errno));
}
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;
}

View File

@ -1,216 +0,0 @@
/* 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>
/* General shared types */
typedef enum
{
META_FRAME_ALLOWS_DELETE = 1 << 0,
META_FRAME_ALLOWS_MENU = 1 << 1,
META_FRAME_ALLOWS_MINIMIZE = 1 << 2,
META_FRAME_ALLOWS_MAXIMIZE = 1 << 3,
META_FRAME_ALLOWS_RESIZE = 1 << 4,
META_FRAME_TRANSIENT = 1 << 5,
META_FRAME_HAS_FOCUS = 1 << 6,
META_FRAME_SHADED = 1 << 7,
META_FRAME_STUCK = 1 << 8
} MetaFrameFlags;
typedef enum
{
META_FRAME_CONTROL_NONE,
META_FRAME_CONTROL_TITLE,
META_FRAME_CONTROL_DELETE,
META_FRAME_CONTROL_MENU,
META_FRAME_CONTROL_MINIMIZE,
META_FRAME_CONTROL_MAXIMIZE,
META_FRAME_CONTROL_RESIZE_SE,
META_FRAME_CONTROL_RESIZE_S,
META_FRAME_CONTROL_RESIZE_SW,
META_FRAME_CONTROL_RESIZE_N,
META_FRAME_CONTROL_RESIZE_NE,
META_FRAME_CONTROL_RESIZE_NW,
META_FRAME_CONTROL_RESIZE_W,
META_FRAME_CONTROL_RESIZE_E
} MetaFrameControl;
/* Now the IPC mess */
/* This thing badly violates the KISS principle. */
/* 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
*/
/* (and lo and behold, our IPC is kind of lame) */
/* We increment this when we change this header, so we can
* check for mismatched UI slave and WM
*/
#define META_MESSAGES_VERSION 2
/* 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
/* This is totally useless of course. Playing around. */
#define META_MESSAGE_CHECKSUM(msg) ((msg)->header.length | (msg)->header.serial << 16)
#define META_MESSAGE_FOOTER(msg) ((MetaMessageFooter*) (((char*)(msg)) + ((msg)->header.length - sizeof (MetaMessageFooter))));
#define META_MESSAGE_LENGTH(real_type) \
(G_STRUCT_OFFSET (real_type, footer) + sizeof (MetaMessageFooter))
#define META_MESSAGE_MAX_SIZE (sizeof(MetaMessage));
#define META_MESSAGE_MAX_VERSION_LEN 15
#define META_MESSAGE_MAX_HOST_ALIAS_LEN 50
#define META_MESSAGE_MAX_TIP_LEN 128
typedef union _MetaMessage MetaMessage;
typedef struct _MetaMessageHeader MetaMessageHeader;
typedef struct _MetaMessageFooter MetaMessageFooter;
typedef struct _MetaMessageCheck MetaMessageCheck;
typedef struct _MetaMessageShowTip MetaMessageShowTip;
typedef struct _MetaMessageHideTip MetaMessageHideTip;
typedef struct _MetaMessageShowWindowMenu MetaMessageShowWindowMenu;
typedef struct _MetaMessageHideWindowMenu MetaMessageHideWindowMenu;
typedef enum
{
/* Keep NullCode and CheckCode unchanged, as with the escape sequence,
* so we can check old UI slaves.
*/
MetaMessageNullCode,
MetaMessageCheckCode,
MetaMessageShowTipCode,
MetaMessageHideTipCode,
MetaMessageShowWindowMenuCode,
MetaMessageHideWindowMenuCode
} MetaMessageCode;
struct _MetaMessageHeader
{
MetaMessageCode message_code;
int length;
int serial;
int request_serial; /* 0 if none */
};
/* The footer thing was pretty much just a debug hack and could die. */
struct _MetaMessageFooter
{
int checksum;
};
/* 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;
MetaMessageFooter footer;
};
struct _MetaMessageShowTip
{
MetaMessageHeader header;
int root_x;
int root_y;
char markup[META_MESSAGE_MAX_TIP_LEN + 1];
MetaMessageFooter footer;
};
struct _MetaMessageHideTip
{
MetaMessageHeader header;
/* just hides the current tip */
MetaMessageFooter footer;
};
typedef enum
{
META_MESSAGE_MENU_DELETE = 1 << 0,
META_MESSAGE_MENU_MINIMIZE = 1 << 1,
META_MESSAGE_MENU_UNMAXIMIZE = 1 << 2,
META_MESSAGE_MENU_MAXIMIZE = 1 << 3,
META_MESSAGE_MENU_UNSHADE = 1 << 4,
META_MESSAGE_MENU_SHADE = 1 << 5,
META_MESSAGE_MENU_UNSTICK = 1 << 6,
META_MESSAGE_MENU_STICK = 1 << 7,
META_MESSAGE_MENU_WORKSPACES = 1 << 8
} MetaMessageWindowMenuOps;
struct _MetaMessageShowWindowMenu
{
MetaMessageHeader header;
MetaMessageWindowMenuOps ops;
MetaMessageWindowMenuOps insensitive;
gulong window;
int root_x;
int root_y;
guint32 timestamp;
int button;
MetaMessageFooter footer;
};
struct _MetaMessageHideWindowMenu
{
MetaMessageHeader header;
MetaMessageFooter footer;
};
union _MetaMessage
{
MetaMessageHeader header;
MetaMessageCheck check;
MetaMessageShowTip show_tip;
MetaMessageShowTip hide_tip;
MetaMessageShowWindowMenu show_menu;
MetaMessageHideWindowMenu hide_menu;
};
/* Slave-side message send/read code */
void meta_message_send_check (void);
#endif

View File

@ -77,6 +77,7 @@ static void meta_window_hide (MetaWindow *window);
static void meta_window_move_resize_internal (MetaWindow *window, static void meta_window_move_resize_internal (MetaWindow *window,
gboolean is_configure_request, gboolean is_configure_request,
int resize_gravity,
int root_x_nw, int root_x_nw,
int root_y_nw, int root_y_nw,
int w, int w,
@ -158,6 +159,19 @@ meta_window_new (MetaDisplay *display, Window xwindow,
if (attrs.border_width != 0) if (attrs.border_width != 0)
XSetWindowBorderWidth (display->xdisplay, xwindow, 0); XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
/* Get rid of weird gravities */
if (attrs.win_gravity != NorthWestGravity)
{
XSetWindowAttributes set_attrs;
set_attrs.win_gravity = NorthWestGravity;
XChangeWindowAttributes (display->xdisplay,
xwindow,
CWWinGravity,
&set_attrs);
}
if (meta_error_trap_pop (display) != Success) if (meta_error_trap_pop (display) != Success)
{ {
meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
@ -420,6 +434,7 @@ meta_window_new (MetaDisplay *display, Window xwindow,
* initial map is handled same as configure request * initial map is handled same as configure request
*/ */
meta_window_move_resize_internal (window, TRUE, meta_window_move_resize_internal (window, TRUE,
NorthWestGravity,
window->size_hints.x, window->size_hints.x,
window->size_hints.y, window->size_hints.y,
window->size_hints.width, window->size_hints.width,
@ -1040,6 +1055,7 @@ adjust_for_gravity (MetaWindow *window,
static void static void
meta_window_move_resize_internal (MetaWindow *window, meta_window_move_resize_internal (MetaWindow *window,
gboolean is_configure_request, gboolean is_configure_request,
int resize_gravity,
int root_x_nw, int root_x_nw,
int root_y_nw, int root_y_nw,
int w, int w,
@ -1053,6 +1069,13 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean need_move_frame = FALSE; gboolean need_move_frame = FALSE;
gboolean need_resize_client = FALSE; gboolean need_resize_client = FALSE;
gboolean need_resize_frame = FALSE; gboolean need_resize_frame = FALSE;
int size_dx;
int size_dy;
int pos_dx;
int pos_dy;
int frame_size_dx;
int frame_size_dy;
int client_gravity;
{ {
int oldx, oldy; int oldx, oldy;
@ -1074,6 +1097,9 @@ meta_window_move_resize_internal (MetaWindow *window,
h != window->rect.height) h != window->rect.height)
need_resize_client = TRUE; need_resize_client = TRUE;
size_dx = w - window->rect.width;
size_dy = h - window->rect.height;
window->rect.width = w; window->rect.width = w;
window->rect.height = h; window->rect.height = h;
@ -1092,6 +1118,9 @@ meta_window_move_resize_internal (MetaWindow *window,
new_h != window->frame->rect.height) new_h != window->frame->rect.height)
need_resize_frame = TRUE; need_resize_frame = TRUE;
frame_size_dx = new_w - window->frame->rect.width;
frame_size_dy = new_h - window->frame->rect.height;
window->frame->rect.width = new_w; window->frame->rect.width = new_w;
window->frame->rect.height = new_h; window->frame->rect.height = new_h;
@ -1099,6 +1128,11 @@ meta_window_move_resize_internal (MetaWindow *window,
window->frame->rect.width, window->frame->rect.width,
window->frame->rect.height); window->frame->rect.height);
} }
else
{
frame_size_dx = 0;
frame_size_dy = 0;
}
if (is_configure_request) if (is_configure_request)
{ {
@ -1117,6 +1151,39 @@ meta_window_move_resize_internal (MetaWindow *window,
root_x_nw, root_y_nw); root_x_nw, root_y_nw);
} }
/* There can be somewhat bogus interactions between gravity
* and the position constraints (with position contraints
* basically breaking gravity). Not sure how to fix this.
*/
/* If client is staying fixed on the east during resize, then we
* have to move the west edge.
*/
switch (resize_gravity)
{
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
root_x_nw -= size_dx;
break;
default:
break;
}
/* If client is staying fixed on the south during resize,
* we have to move the north edge
*/
switch (resize_gravity)
{
case SouthGravity:
case SouthEastGravity:
case SouthWestGravity:
root_y_nw -= size_dy;
break;
default:
break;
}
constrain_position (window, constrain_position (window,
window->frame ? &fgeom : NULL, window->frame ? &fgeom : NULL,
root_x_nw, root_y_nw, root_x_nw, root_y_nw,
@ -1146,6 +1213,9 @@ meta_window_move_resize_internal (MetaWindow *window,
/* window->rect.x, window->rect.y are relative to frame, /* window->rect.x, window->rect.y are relative to frame,
* remember they are the server coords * remember they are the server coords
*/ */
pos_dx = fgeom.left_width - window->rect.x;
pos_dy = fgeom.top_height - window->rect.y;
window->rect.x = fgeom.left_width; window->rect.x = fgeom.left_width;
window->rect.y = fgeom.top_height; window->rect.y = fgeom.top_height;
} }
@ -1155,6 +1225,9 @@ meta_window_move_resize_internal (MetaWindow *window,
root_y_nw != window->rect.y) root_y_nw != window->rect.y)
need_move_client = TRUE; need_move_client = TRUE;
pos_dx = root_x_nw - window->rect.x;
pos_dy = root_y_nw - window->rect.y;
window->rect.x = root_x_nw; window->rect.x = root_x_nw;
window->rect.y = root_y_nw; window->rect.y = root_y_nw;
} }
@ -1188,7 +1261,9 @@ meta_window_move_resize_internal (MetaWindow *window,
!(need_resize_client || need_resize_frame)) !(need_resize_client || need_resize_frame))
need_configure_notify = TRUE; need_configure_notify = TRUE;
/* Sync our new size/pos with X as efficiently as possible */ /* The rest of this function syncs our new size/pos with X as
* efficiently as possible
*/
values.border_width = 0; values.border_width = 0;
values.x = window->rect.x; values.x = window->rect.x;
@ -1227,7 +1302,9 @@ meta_window_move_resize_internal (MetaWindow *window,
/* Now do the frame */ /* Now do the frame */
if (window->frame) if (window->frame)
{
meta_frame_sync_to_window (window->frame, need_move_frame, need_resize_frame); meta_frame_sync_to_window (window->frame, need_move_frame, need_resize_frame);
}
if (need_configure_notify) if (need_configure_notify)
send_configure_notify (window); send_configure_notify (window);
@ -1248,7 +1325,9 @@ meta_window_resize (MetaWindow *window,
meta_window_get_position (window, &x, &y); meta_window_get_position (window, &x, &y);
meta_window_move_resize_internal (window, FALSE, x, y, w, h); meta_window_move_resize_internal (window, FALSE,
NorthWestGravity,
x, y, w, h);
} }
void void
@ -1257,6 +1336,7 @@ meta_window_move (MetaWindow *window,
int root_y_nw) int root_y_nw)
{ {
meta_window_move_resize_internal (window, FALSE, meta_window_move_resize_internal (window, FALSE,
NorthWestGravity,
root_x_nw, root_y_nw, root_x_nw, root_y_nw,
window->rect.width, window->rect.width,
window->rect.height); window->rect.height);
@ -1270,10 +1350,26 @@ meta_window_move_resize (MetaWindow *window,
int h) int h)
{ {
meta_window_move_resize_internal (window, FALSE, meta_window_move_resize_internal (window, FALSE,
NorthWestGravity,
root_x_nw, root_y_nw, root_x_nw, root_y_nw,
w, h); w, h);
} }
void
meta_window_resize_with_gravity (MetaWindow *window,
int w,
int h,
int gravity)
{
int x, y;
meta_window_get_position (window, &x, &y);
meta_window_move_resize_internal (window, FALSE,
gravity,
x, y, w, h);
}
void void
meta_window_move_resize_now (MetaWindow *window) meta_window_move_resize_now (MetaWindow *window)
{ {
@ -1921,6 +2017,7 @@ process_configure_request (MetaWindow *window,
window->size_hints.height = height; window->size_hints.height = height;
meta_window_move_resize_internal (window, TRUE, meta_window_move_resize_internal (window, TRUE,
NorthWestGravity,
window->size_hints.x, window->size_hints.x,
window->size_hints.y, window->size_hints.y,
window->size_hints.width, window->size_hints.width,
@ -3392,3 +3489,23 @@ meta_window_shares_some_workspace (MetaWindow *window,
return FALSE; return FALSE;
} }
void
meta_window_set_gravity (MetaWindow *window,
int gravity)
{
XSetWindowAttributes attrs;
meta_verbose ("Setting gravity of %s to %d\n", window->desc, gravity);
attrs.win_gravity = gravity;
meta_error_trap_push (window->display);
XChangeWindowAttributes (window->display->xdisplay,
window->xwindow,
CWWinGravity,
&attrs);
meta_error_trap_pop (window->display);
}

View File

@ -234,6 +234,11 @@ void meta_window_move_resize (MetaWindow *window,
int root_y_nw, int root_y_nw,
int w, int w,
int h); int h);
void meta_window_resize_with_gravity (MetaWindow *window,
int w,
int h,
int gravity);
/* This recalcs the window/frame size, and recalcs the frame /* This recalcs the window/frame size, and recalcs the frame
* size/contents as well. * size/contents as well.
*/ */
@ -278,4 +283,7 @@ void meta_window_show_menu (MetaWindow *window,
gboolean meta_window_shares_some_workspace (MetaWindow *window, gboolean meta_window_shares_some_workspace (MetaWindow *window,
MetaWindow *with); MetaWindow *with);
void meta_window_set_gravity (MetaWindow *window,
int gravity);
#endif #endif