Commit 0feac37c authored by rhp's avatar rhp
Browse files

...

parent 834452ca
......@@ -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
......
......@@ -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;
......
......@@ -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);
}
......@@ -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
*/
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment