mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 03:22:04 +00:00
...
This commit is contained in:
parent
834452ca2c
commit
0feac37c5b
@ -78,7 +78,8 @@ meta_display_open (const char *name)
|
||||
"WM_PROTOCOLS",
|
||||
"WM_TAKE_FOCUS",
|
||||
"WM_DELETE_WINDOW",
|
||||
"WM_STATE"
|
||||
"WM_STATE",
|
||||
"_NET_CLOSE_WINDOW"
|
||||
};
|
||||
Atom atoms[G_N_ELEMENTS(atom_names)];
|
||||
|
||||
@ -155,6 +156,7 @@ meta_display_open (const char *name)
|
||||
display->atom_wm_take_focus = atoms[2];
|
||||
display->atom_wm_delete_window = atoms[3];
|
||||
display->atom_wm_state = atoms[4];
|
||||
display->atom_net_close_window = atoms[5];
|
||||
|
||||
/* Now manage all existing windows */
|
||||
tmp = display->screens;
|
||||
@ -494,6 +496,18 @@ event_queue_callback (MetaEventQueue *queue,
|
||||
case ColormapNotify:
|
||||
break;
|
||||
case ClientMessage:
|
||||
if (window)
|
||||
{
|
||||
if (event->xclient.message_type ==
|
||||
display->atom_net_close_window)
|
||||
{
|
||||
/* I think the wm spec should maybe put a time
|
||||
* in this message, CurrentTime here is sort of
|
||||
* bogus. But it rarely matters most likely.
|
||||
*/
|
||||
meta_window_delete (window, CurrentTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MappingNotify:
|
||||
break;
|
||||
@ -708,7 +722,18 @@ meta_spew_event (MetaDisplay *display,
|
||||
name = "ColormapNotify";
|
||||
break;
|
||||
case ClientMessage:
|
||||
name = "ClientMessage";
|
||||
{
|
||||
char *str;
|
||||
name = "ClientMessage";
|
||||
meta_error_trap_push (display);
|
||||
str = XGetAtomName (display->xdisplay,
|
||||
event->xclient.message_type);
|
||||
meta_error_trap_pop (display);
|
||||
extra = g_strdup_printf ("type: %s format: %d\n",
|
||||
str ? str : "(unknown atom)",
|
||||
event->xclient.format);
|
||||
XFree (str);
|
||||
}
|
||||
break;
|
||||
case MappingNotify:
|
||||
name = "MappingNotify";
|
||||
|
@ -44,6 +44,7 @@ struct _MetaDisplay
|
||||
Atom atom_wm_take_focus;
|
||||
Atom atom_wm_delete_window;
|
||||
Atom atom_wm_state;
|
||||
Atom atom_net_close_window;
|
||||
|
||||
/* This is the actual window from focus events,
|
||||
* not the one we last set
|
||||
|
27
src/frame.c
27
src/frame.c
@ -169,6 +169,8 @@ meta_frame_calc_geometry (MetaFrame *frame,
|
||||
|
||||
frame->child_x = geom.left_width;
|
||||
frame->child_y = geom.top_height;
|
||||
frame->right_width = geom.right_width;
|
||||
frame->bottom_height = geom.bottom_height;
|
||||
|
||||
frame->rect.width = frame->rect.width + geom.left_width + geom.right_width;
|
||||
frame->rect.height = frame->rect.height + geom.top_height + geom.bottom_height;
|
||||
@ -787,13 +789,21 @@ meta_frame_event (MetaFrame *frame,
|
||||
else if (control == META_FRAME_CONTROL_DELETE &&
|
||||
event->xbutton.button == 1)
|
||||
{
|
||||
/* FIXME delete event */
|
||||
meta_verbose ("Close control clicked on %s\n",
|
||||
frame->window->desc);
|
||||
grab_action (frame, META_FRAME_ACTION_DELETING,
|
||||
event->xbutton.time);
|
||||
frame->grab->start_button = event->xbutton.button;
|
||||
}
|
||||
else if (control == META_FRAME_CONTROL_MAXIMIZE &&
|
||||
event->xbutton.button == 1)
|
||||
{
|
||||
meta_verbose ("Maximize control clicked on %s\n",
|
||||
frame->window->desc);
|
||||
grab_action (frame, META_FRAME_ACTION_TOGGLING_MAXIMIZE,
|
||||
event->xbutton.time);
|
||||
frame->grab->start_button = event->xbutton.button;
|
||||
}
|
||||
else if (control == META_FRAME_CONTROL_RESIZE_SE &&
|
||||
event->xbutton.button == 1)
|
||||
{
|
||||
@ -874,6 +884,21 @@ meta_frame_event (MetaFrame *frame,
|
||||
if (frame->current_control == META_FRAME_CONTROL_DELETE)
|
||||
meta_window_delete (frame->window, event->xbutton.time);
|
||||
break;
|
||||
case META_FRAME_ACTION_TOGGLING_MAXIMIZE:
|
||||
/* Must ungrab before getting "real" control position */
|
||||
ungrab_action (frame, event->xbutton.time);
|
||||
update_current_control (frame,
|
||||
event->xbutton.x_root,
|
||||
event->xbutton.y_root);
|
||||
/* delete if we're still over the button */
|
||||
if (frame->current_control == META_FRAME_CONTROL_MAXIMIZE)
|
||||
{
|
||||
if (frame->window->maximized)
|
||||
meta_window_unmaximize (frame->window);
|
||||
else
|
||||
meta_window_maximize (frame->window);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
meta_warning ("Unhandled action in button release\n");
|
||||
break;
|
||||
|
@ -29,6 +29,7 @@ typedef enum
|
||||
META_FRAME_ACTION_NONE,
|
||||
META_FRAME_ACTION_MOVING,
|
||||
META_FRAME_ACTION_DELETING,
|
||||
META_FRAME_ACTION_TOGGLING_MAXIMIZE,
|
||||
META_FRAME_ACTION_RESIZING_SE
|
||||
} MetaFrameAction;
|
||||
|
||||
@ -48,6 +49,8 @@ struct _MetaFrame
|
||||
MetaRectangle rect;
|
||||
int child_x;
|
||||
int child_y;
|
||||
int right_width;
|
||||
int bottom_height;
|
||||
|
||||
gpointer theme_data;
|
||||
gulong bg_pixel;
|
||||
|
47
src/menu.c
47
src/menu.c
@ -175,6 +175,27 @@ meta_window_menu_hide (void)
|
||||
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
|
||||
activate_cb (GtkWidget *menuitem, gpointer data)
|
||||
{
|
||||
@ -182,9 +203,29 @@ activate_cb (GtkWidget *menuitem, gpointer data)
|
||||
|
||||
md = data;
|
||||
|
||||
meta_ui_warning ("Activated menuitem\n");
|
||||
|
||||
gtk_widget_destroy (menu);
|
||||
switch (md->op)
|
||||
{
|
||||
case META_MESSAGE_MENU_DELETE:
|
||||
close_window (md->window);
|
||||
break;
|
||||
|
||||
case META_MESSAGE_MENU_MINIMIZE:
|
||||
break;
|
||||
|
||||
case META_MESSAGE_MENU_MAXIMIZE:
|
||||
gdk_error_trap_push ();
|
||||
gdk_window_maximize (md->window);
|
||||
gdk_flush ();
|
||||
gdk_error_trap_pop ();
|
||||
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);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ elif test -z "$DEBUG"; then
|
||||
DEBUG=gdb
|
||||
fi
|
||||
|
||||
Xnest :1 -scrns $SCREENS -geometry 270x270 &
|
||||
Xnest :1 -scrns $SCREENS -geometry 640x480 &
|
||||
DISPLAY=:1 xsetroot -solid royalblue3
|
||||
METACITY_UISLAVE_DIR=./uislave DISPLAY=:1 unst libtool --mode=execute $DEBUG ./metacity
|
||||
killall Xnest
|
||||
|
@ -175,6 +175,27 @@ meta_window_menu_hide (void)
|
||||
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
|
||||
activate_cb (GtkWidget *menuitem, gpointer data)
|
||||
{
|
||||
@ -182,9 +203,29 @@ activate_cb (GtkWidget *menuitem, gpointer data)
|
||||
|
||||
md = data;
|
||||
|
||||
meta_ui_warning ("Activated menuitem\n");
|
||||
|
||||
gtk_widget_destroy (menu);
|
||||
switch (md->op)
|
||||
{
|
||||
case META_MESSAGE_MENU_DELETE:
|
||||
close_window (md->window);
|
||||
break;
|
||||
|
||||
case META_MESSAGE_MENU_MINIMIZE:
|
||||
break;
|
||||
|
||||
case META_MESSAGE_MENU_MAXIMIZE:
|
||||
gdk_error_trap_push ();
|
||||
gdk_window_maximize (md->window);
|
||||
gdk_flush ();
|
||||
gdk_error_trap_pop ();
|
||||
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);
|
||||
}
|
||||
|
113
src/window.c
113
src/window.c
@ -128,6 +128,9 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
window->size_hints.y = attrs.y;
|
||||
window->size_hints.width = attrs.width;
|
||||
window->size_hints.height = attrs.height;
|
||||
|
||||
/* And this is our unmaximized size */
|
||||
window->saved_rect = window->rect;
|
||||
|
||||
window->depth = attrs.depth;
|
||||
window->xvisual = attrs.visual;
|
||||
@ -139,6 +142,7 @@ meta_window_new (MetaDisplay *display, Window xwindow)
|
||||
window->frame = NULL;
|
||||
window->has_focus = FALSE;
|
||||
|
||||
window->maximized = FALSE;
|
||||
window->initially_iconic = FALSE;
|
||||
window->minimized = FALSE;
|
||||
window->iconic = FALSE;
|
||||
@ -198,8 +202,10 @@ meta_window_free (MetaWindow *window)
|
||||
}
|
||||
|
||||
g_assert (window->workspaces == NULL);
|
||||
|
||||
/* FIXME restore original size if window has maximized */
|
||||
|
||||
set_wm_state (window, WithdrawnState);
|
||||
set_wm_state (window, WithdrawnState);
|
||||
|
||||
meta_display_unregister_x_window (window->display, window->xwindow);
|
||||
|
||||
@ -319,7 +325,7 @@ meta_window_minimize (MetaWindow *window)
|
||||
if (!window->minimized)
|
||||
{
|
||||
window->minimized = TRUE;
|
||||
meta_window_hide (window);
|
||||
meta_window_queue_calc_showing (window);
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +335,60 @@ meta_window_unminimize (MetaWindow *window)
|
||||
if (window->minimized)
|
||||
{
|
||||
window->minimized = FALSE;
|
||||
meta_window_show (window);
|
||||
meta_window_queue_calc_showing (window);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_maximize (MetaWindow *window)
|
||||
{
|
||||
if (!window->maximized)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
window->maximized = TRUE;
|
||||
|
||||
/* save size */
|
||||
window->saved_rect = window->rect;
|
||||
if (window->frame)
|
||||
{
|
||||
window->saved_rect.x += window->frame->rect.x;
|
||||
window->saved_rect.y += window->frame->rect.y;
|
||||
}
|
||||
|
||||
/* resize to current size with new maximization constraint */
|
||||
meta_window_resize (window,
|
||||
window->rect.width, window->rect.height);
|
||||
|
||||
/* move to top left corner */
|
||||
x = window->screen->active_workspace->workarea.x;
|
||||
y = window->screen->active_workspace->workarea.y;
|
||||
if (window->frame)
|
||||
{
|
||||
x += window->frame->child_x;
|
||||
y += window->frame->child_y;
|
||||
}
|
||||
|
||||
meta_window_move (window, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_unmaximize (MetaWindow *window)
|
||||
{
|
||||
if (window->maximized)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
window->maximized = FALSE;
|
||||
|
||||
meta_window_resize (window,
|
||||
window->saved_rect.width,
|
||||
window->saved_rect.height);
|
||||
|
||||
meta_window_move (window,
|
||||
window->saved_rect.x,
|
||||
window->saved_rect.y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,7 +434,10 @@ meta_window_move (MetaWindow *window,
|
||||
{
|
||||
window->frame->rect.x = new_x;
|
||||
window->frame->rect.y = new_y;
|
||||
|
||||
/* window->rect.x, window->rect.y remain relative to frame,
|
||||
* remember they are the server coords
|
||||
*/
|
||||
|
||||
XMoveWindow (window->display->xdisplay,
|
||||
window->frame->xwindow,
|
||||
window->frame->rect.x,
|
||||
@ -1003,17 +1065,48 @@ constrain_size (MetaWindow *window,
|
||||
*/
|
||||
int delta;
|
||||
double min_aspect, max_aspect;
|
||||
int minw, minh, maxw, maxh, fullw, fullh;
|
||||
|
||||
#define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) )
|
||||
|
||||
/* Get the allowed size ranges, considering maximized, etc. */
|
||||
fullw = window->screen->active_workspace->workarea.width;
|
||||
fullh = window->screen->active_workspace->workarea.height;
|
||||
if (window->frame)
|
||||
{
|
||||
fullw -= window->frame->child_x + window->frame->right_width;
|
||||
fullh -= window->frame->child_y + window->frame->bottom_height;
|
||||
}
|
||||
|
||||
maxw = window->size_hints.max_width;
|
||||
maxh = window->size_hints.max_height;
|
||||
if (window->maximized)
|
||||
{
|
||||
maxw = MIN (maxw, fullw);
|
||||
maxh = MIN (maxh, fullh);
|
||||
}
|
||||
|
||||
minw = window->size_hints.min_width;
|
||||
minh = window->size_hints.min_height;
|
||||
if (window->maximized)
|
||||
{
|
||||
minw = MAX (minw, fullw);
|
||||
minh = MAX (minh, fullh);
|
||||
}
|
||||
|
||||
/* Check that fullscreen doesn't exceed max width hint,
|
||||
* if so then snap back to max width hint
|
||||
*/
|
||||
if (minw > maxw)
|
||||
minw = maxw;
|
||||
if (minh > maxh)
|
||||
minh = maxh;
|
||||
|
||||
/* clamp width and height to min and max values
|
||||
*/
|
||||
width = CLAMP (width,
|
||||
window->size_hints.min_width,
|
||||
window->size_hints.max_width);
|
||||
height = CLAMP (height,
|
||||
window->size_hints.min_height,
|
||||
window->size_hints.max_height);
|
||||
width = CLAMP (width, minw, maxw);
|
||||
|
||||
height = CLAMP (height, minh, maxh);
|
||||
|
||||
/* shrink to base + N * inc
|
||||
*/
|
||||
|
19
src/window.h
19
src/window.h
@ -39,12 +39,14 @@ struct _MetaWindow
|
||||
char *desc; /* used in debug spew */
|
||||
char *title;
|
||||
|
||||
/* Whether we're maximized */
|
||||
guint maximized : 1;
|
||||
/* Mapped is what we think the mapped state should be;
|
||||
* so if we get UnmapNotify and mapped == TRUE then
|
||||
* it's a withdraw, if mapped == FALSE the UnmapNotify
|
||||
* is caused by us.
|
||||
*/
|
||||
guint mapped : 1;
|
||||
guint mapped : 1 ;
|
||||
/* Minimize is the state controlled by the minimize button */
|
||||
guint minimized : 1;
|
||||
/* Iconic is the state in WM_STATE; happens for workspaces/shading
|
||||
@ -67,8 +69,19 @@ struct _MetaWindow
|
||||
*/
|
||||
guint has_focus : 1;
|
||||
|
||||
/* The size we set the window to last. */
|
||||
/* The size we set the window to last (i.e. what we believe
|
||||
* to be its actual size on the server). The x, y are
|
||||
* the actual server-side x,y so are relative to the frame
|
||||
* or the root window as appropriate.
|
||||
*/
|
||||
MetaRectangle rect;
|
||||
|
||||
/* The geometry to restore when we unmaximize.
|
||||
* The position is in root window coords, even if
|
||||
* there's a frame, which contrasts with window->rect
|
||||
* above.
|
||||
*/
|
||||
MetaRectangle saved_rect;
|
||||
|
||||
/* Requested geometry */
|
||||
int border_width;
|
||||
@ -86,6 +99,8 @@ void meta_window_unminimize (MetaWindow *window);
|
||||
void meta_window_resize (MetaWindow *window,
|
||||
int w,
|
||||
int h);
|
||||
void meta_window_maximize (MetaWindow *window);
|
||||
void meta_window_unmaximize (MetaWindow *window);
|
||||
|
||||
/* args to move are window pos, not frame pos */
|
||||
void meta_window_move (MetaWindow *window,
|
||||
|
@ -34,6 +34,14 @@ meta_workspace_new (MetaScreen *screen)
|
||||
workspace->screen->display->workspaces =
|
||||
g_list_append (workspace->screen->display->workspaces, workspace);
|
||||
workspace->windows = NULL;
|
||||
|
||||
/* This may have something to do with the strut hints
|
||||
* eventually
|
||||
*/
|
||||
workspace->workarea.x = 0;
|
||||
workspace->workarea.y = 0;
|
||||
workspace->workarea.width = WidthOfScreen (screen->xscreen);
|
||||
workspace->workarea.height = HeightOfScreen (screen->xscreen);
|
||||
|
||||
return workspace;
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ struct _MetaWorkspace
|
||||
MetaScreen *screen;
|
||||
|
||||
GList *windows;
|
||||
|
||||
MetaRectangle workarea;
|
||||
};
|
||||
|
||||
MetaWorkspace* meta_workspace_new (MetaScreen *screen);
|
||||
|
Loading…
Reference in New Issue
Block a user