mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 23:50:41 -05:00
...
This commit is contained in:
parent
ed2af7d22f
commit
43f807c5e1
@ -73,7 +73,6 @@ Makefile
|
||||
intl/Makefile
|
||||
po/Makefile.in
|
||||
src/Makefile
|
||||
src/uislave/Makefile
|
||||
])
|
||||
|
||||
|
||||
|
@ -3,5 +3,3 @@ Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
metacity
|
||||
messagequeue.h
|
||||
messagequeue.c
|
||||
|
@ -10,6 +10,8 @@ metacity_SOURCES= \
|
||||
errors.h \
|
||||
eventqueue.c \
|
||||
eventqueue.h \
|
||||
fixedtip.c \
|
||||
fixedtip.h \
|
||||
frame.c \
|
||||
frame.h \
|
||||
frames.c \
|
||||
|
@ -98,6 +98,7 @@ meta_core_user_move (Display *xdisplay,
|
||||
void
|
||||
meta_core_user_resize (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int gravity,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
@ -111,7 +112,7 @@ meta_core_user_resize (Display *xdisplay,
|
||||
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
|
||||
|
||||
window->user_has_resized = TRUE;
|
||||
meta_window_resize (window, width, height);
|
||||
meta_window_resize_with_gravity (window, width, height, gravity);
|
||||
}
|
||||
|
||||
void
|
||||
@ -375,4 +376,3 @@ meta_core_show_window_menu (Display *xdisplay,
|
||||
meta_window_show_menu (window, root_x, root_y, button, timestamp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ void meta_core_user_move (Display *xdisplay,
|
||||
int y);
|
||||
void meta_core_user_resize (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int gravity,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
@ -84,7 +85,6 @@ void meta_core_change_workspace (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int new_workspace);
|
||||
|
||||
|
||||
int meta_core_get_num_workspaces (Screen *xscreen);
|
||||
int meta_core_get_active_workspace (Screen *xscreen);
|
||||
int meta_core_get_frame_workspace (Display *xdisplay,
|
||||
|
@ -36,7 +36,8 @@ expose_handler (GtkTooltips *tooltips)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (tip == NULL)
|
||||
@ -74,5 +75,9 @@ meta_fixed_tip_show (int root_x, int root_y,
|
||||
void
|
||||
meta_fixed_tip_hide (void)
|
||||
{
|
||||
if (tip)
|
||||
{
|
||||
gtk_widget_destroy (tip);
|
||||
tip = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,10 @@
|
||||
#define META_FIXED_TIP_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);
|
||||
void meta_fixed_tip_hide (void);
|
||||
|
||||
|
949
src/frames.c
949
src/frames.c
File diff suppressed because it is too large
Load Diff
16
src/frames.h
16
src/frames.h
@ -52,7 +52,14 @@ typedef enum
|
||||
META_FRAME_STATUS_CLICKING_MAXIMIZE,
|
||||
META_FRAME_STATUS_CLICKING_DELETE,
|
||||
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;
|
||||
|
||||
/* This is one widget that manages all the window frames
|
||||
@ -90,13 +97,18 @@ struct _MetaFrames
|
||||
|
||||
GHashTable *frames;
|
||||
|
||||
guint tooltip_timeout;
|
||||
MetaUIFrame *last_motion_frame;
|
||||
|
||||
/* The below is all for grabs */
|
||||
MetaFrameStatus grab_status;
|
||||
MetaUIFrame *grab_frame;
|
||||
/* initial mouse position for drags */
|
||||
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;
|
||||
/* initial window size for drags */
|
||||
int start_window_w, start_window_h;
|
||||
/* button doing the dragging */
|
||||
int start_button;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#! /bin/bash
|
||||
if test -z "$SCREENS"; then
|
||||
SCREENS=2
|
||||
SCREENS=1
|
||||
fi
|
||||
|
||||
if test "$DEBUG" = none; then
|
||||
|
@ -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@
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
121
src/window.c
121
src/window.c
@ -77,6 +77,7 @@ static void meta_window_hide (MetaWindow *window);
|
||||
|
||||
static void meta_window_move_resize_internal (MetaWindow *window,
|
||||
gboolean is_configure_request,
|
||||
int resize_gravity,
|
||||
int root_x_nw,
|
||||
int root_y_nw,
|
||||
int w,
|
||||
@ -158,6 +159,19 @@ meta_window_new (MetaDisplay *display, Window xwindow,
|
||||
if (attrs.border_width != 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)
|
||||
{
|
||||
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
|
||||
*/
|
||||
meta_window_move_resize_internal (window, TRUE,
|
||||
NorthWestGravity,
|
||||
window->size_hints.x,
|
||||
window->size_hints.y,
|
||||
window->size_hints.width,
|
||||
@ -1040,6 +1055,7 @@ adjust_for_gravity (MetaWindow *window,
|
||||
static void
|
||||
meta_window_move_resize_internal (MetaWindow *window,
|
||||
gboolean is_configure_request,
|
||||
int resize_gravity,
|
||||
int root_x_nw,
|
||||
int root_y_nw,
|
||||
int w,
|
||||
@ -1053,6 +1069,13 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
gboolean need_move_frame = FALSE;
|
||||
gboolean need_resize_client = 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;
|
||||
@ -1074,6 +1097,9 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
h != window->rect.height)
|
||||
need_resize_client = TRUE;
|
||||
|
||||
size_dx = w - window->rect.width;
|
||||
size_dy = h - window->rect.height;
|
||||
|
||||
window->rect.width = w;
|
||||
window->rect.height = h;
|
||||
|
||||
@ -1092,6 +1118,9 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
new_h != window->frame->rect.height)
|
||||
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.height = new_h;
|
||||
|
||||
@ -1099,6 +1128,11 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
window->frame->rect.width,
|
||||
window->frame->rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_size_dx = 0;
|
||||
frame_size_dy = 0;
|
||||
}
|
||||
|
||||
if (is_configure_request)
|
||||
{
|
||||
@ -1117,6 +1151,39 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
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,
|
||||
window->frame ? &fgeom : NULL,
|
||||
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,
|
||||
* 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.y = fgeom.top_height;
|
||||
}
|
||||
@ -1155,6 +1225,9 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
root_y_nw != window->rect.y)
|
||||
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.y = root_y_nw;
|
||||
}
|
||||
@ -1188,7 +1261,9 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
!(need_resize_client || need_resize_frame))
|
||||
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.x = window->rect.x;
|
||||
@ -1227,7 +1302,9 @@ meta_window_move_resize_internal (MetaWindow *window,
|
||||
|
||||
/* Now do the frame */
|
||||
if (window->frame)
|
||||
{
|
||||
meta_frame_sync_to_window (window->frame, need_move_frame, need_resize_frame);
|
||||
}
|
||||
|
||||
if (need_configure_notify)
|
||||
send_configure_notify (window);
|
||||
@ -1248,7 +1325,9 @@ meta_window_resize (MetaWindow *window,
|
||||
|
||||
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
|
||||
@ -1257,6 +1336,7 @@ meta_window_move (MetaWindow *window,
|
||||
int root_y_nw)
|
||||
{
|
||||
meta_window_move_resize_internal (window, FALSE,
|
||||
NorthWestGravity,
|
||||
root_x_nw, root_y_nw,
|
||||
window->rect.width,
|
||||
window->rect.height);
|
||||
@ -1270,10 +1350,26 @@ meta_window_move_resize (MetaWindow *window,
|
||||
int h)
|
||||
{
|
||||
meta_window_move_resize_internal (window, FALSE,
|
||||
NorthWestGravity,
|
||||
root_x_nw, root_y_nw,
|
||||
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
|
||||
meta_window_move_resize_now (MetaWindow *window)
|
||||
{
|
||||
@ -1921,6 +2017,7 @@ process_configure_request (MetaWindow *window,
|
||||
window->size_hints.height = height;
|
||||
|
||||
meta_window_move_resize_internal (window, TRUE,
|
||||
NorthWestGravity,
|
||||
window->size_hints.x,
|
||||
window->size_hints.y,
|
||||
window->size_hints.width,
|
||||
@ -3392,3 +3489,23 @@ meta_window_shares_some_workspace (MetaWindow *window,
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -234,6 +234,11 @@ void meta_window_move_resize (MetaWindow *window,
|
||||
int root_y_nw,
|
||||
int w,
|
||||
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
|
||||
* size/contents as well.
|
||||
*/
|
||||
@ -278,4 +283,7 @@ void meta_window_show_menu (MetaWindow *window,
|
||||
gboolean meta_window_shares_some_workspace (MetaWindow *window,
|
||||
MetaWindow *with);
|
||||
|
||||
void meta_window_set_gravity (MetaWindow *window,
|
||||
int gravity);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user