From 0feac37c5b23870dbd1bdd3ac30e9f5435820217 Mon Sep 17 00:00:00 2001 From: rhp Date: Thu, 7 Jun 2001 05:18:10 +0000 Subject: [PATCH] ... --- src/display.c | 29 +++++++++++- src/display.h | 1 + src/frame.c | 27 ++++++++++- src/frame.h | 3 ++ src/menu.c | 47 ++++++++++++++++-- src/run-metacity.sh | 2 +- src/uislave/menu.c | 47 ++++++++++++++++-- src/window.c | 113 ++++++++++++++++++++++++++++++++++++++++---- src/window.h | 19 +++++++- src/workspace.c | 8 ++++ src/workspace.h | 2 + 11 files changed, 276 insertions(+), 22 deletions(-) diff --git a/src/display.c b/src/display.c index 87a3bfb4c..f9fb8ef55 100644 --- a/src/display.c +++ b/src/display.c @@ -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"; diff --git a/src/display.h b/src/display.h index 6f0925764..4a9df6460 100644 --- a/src/display.h +++ b/src/display.h @@ -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 diff --git a/src/frame.c b/src/frame.c index c10ce98b5..fdd694896 100644 --- a/src/frame.c +++ b/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; diff --git a/src/frame.h b/src/frame.h index 0b5f2a08e..c520b1a2a 100644 --- a/src/frame.h +++ b/src/frame.h @@ -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; diff --git a/src/menu.c b/src/menu.c index 292e99484..81015dd60 100644 --- a/src/menu.c +++ b/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); } diff --git a/src/run-metacity.sh b/src/run-metacity.sh index 40ef0d418..798d711e0 100755 --- a/src/run-metacity.sh +++ b/src/run-metacity.sh @@ -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 diff --git a/src/uislave/menu.c b/src/uislave/menu.c index 292e99484..81015dd60 100644 --- a/src/uislave/menu.c +++ b/src/uislave/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); } diff --git a/src/window.c b/src/window.c index 4b6a75fda..29dd5c1d8 100644 --- a/src/window.c +++ b/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 */ diff --git a/src/window.h b/src/window.h index 70c2a11a3..38d4440a0 100644 --- a/src/window.h +++ b/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, diff --git a/src/workspace.c b/src/workspace.c index d0e2339fd..2e1fb53d7 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -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; } diff --git a/src/workspace.h b/src/workspace.h index dcf808d5b..5cde8a0a6 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -29,6 +29,8 @@ struct _MetaWorkspace MetaScreen *screen; GList *windows; + + MetaRectangle workarea; }; MetaWorkspace* meta_workspace_new (MetaScreen *screen);