diff --git a/src/display.c b/src/display.c index df2169a96..51712250b 100644 --- a/src/display.c +++ b/src/display.c @@ -543,38 +543,7 @@ event_queue_callback (MetaEventQueue *queue, 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); - } - else if (event->xclient.message_type == - display->atom_net_wm_desktop) - { - int space; - MetaWorkspace *workspace; - - space = event->xclient.data.l[0]; - - meta_verbose ("Request to move %s to screen workspace %d\n", - window->desc, space); - - workspace = - meta_display_get_workspace_by_screen_index (display, - window->screen, - space); - - if (workspace) - meta_window_change_workspace (window, workspace); - else - meta_verbose ("No such workspace %d for screen\n", space); - } - } + meta_window_client_message (window, event); break; case MappingNotify: break; diff --git a/src/display.h b/src/display.h index 1b3ef03d7..bc24b28e2 100644 --- a/src/display.h +++ b/src/display.h @@ -34,6 +34,10 @@ typedef struct _MetaUISlave MetaUISlave; typedef struct _MetaWindow MetaWindow; typedef struct _MetaWorkspace MetaWorkspace; +#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 */ + struct _MetaDisplay { char *name; diff --git a/src/frame.c b/src/frame.c index fdeebeef6..7d20aa230 100644 --- a/src/frame.c +++ b/src/frame.c @@ -752,6 +752,37 @@ ungrab_action (MetaFrame *frame, queue_tip (frame); } +static void +get_menu_items (MetaFrame *frame, + MetaFrameInfo *info, + MetaMessageWindowMenuOps *ops, + MetaMessageWindowMenuOps *insensitive) +{ + *ops = 0; + *insensitive = 0; + + if (info->flags & META_FRAME_CONTROL_MAXIMIZE) + { + if (frame->window->maximized) + *ops |= META_MESSAGE_MENU_UNMAXIMIZE; + else + *ops |= META_MESSAGE_MENU_MAXIMIZE; + } + + if (frame->window->shaded) + *ops |= META_MESSAGE_MENU_UNSHADE; + else + *ops |= META_MESSAGE_MENU_SHADE; + + *ops |= (META_MESSAGE_MENU_DELETE | META_MESSAGE_MENU_WORKSPACES | META_MESSAGE_MENU_MINIMIZE); + + if (!(info->flags & META_FRAME_CONTROL_MINIMIZE)) + *insensitive |= META_MESSAGE_MENU_MINIMIZE; + + if (!(info->flags & META_FRAME_CONTROL_DELETE)) + *insensitive |= META_MESSAGE_MENU_DELETE; +} + gboolean meta_frame_event (MetaFrame *frame, XEvent *event) @@ -846,7 +877,9 @@ meta_frame_event (MetaFrame *frame, { int x, y, width, height; MetaFrameInfo info; - + MetaMessageWindowMenuOps ops; + MetaMessageWindowMenuOps insensitive; + meta_verbose ("Menu control clicked on %s\n", frame->window->desc); @@ -863,14 +896,15 @@ meta_frame_event (MetaFrame *frame, */ XUngrabPointer (frame->window->display->xdisplay, event->xbutton.time); + + get_menu_items (frame, &info, &ops, &insensitive); meta_ui_slave_show_window_menu (frame->window->screen->uislave, frame->window, frame->rect.x + x, frame->rect.y + y + height, event->xbutton.button, - META_MESSAGE_MENU_ALL, - META_MESSAGE_MENU_MINIMIZE, + ops, insensitive, event->xbutton.time); } } diff --git a/src/menu.c b/src/menu.c index 5e77abc97..f9687a79b 100644 --- a/src/menu.c +++ b/src/menu.c @@ -24,6 +24,10 @@ #include #include +#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; @@ -48,7 +52,9 @@ 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_SHADE, NULL, N_("_Shade") } + { META_MESSAGE_MENU_UNMAXIMIZE, NULL, N_("_Unmaximize") }, + { META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }, + { META_MESSAGE_MENU_UNSHADE, NULL, N_("U_nshade") } }; static void @@ -218,11 +224,16 @@ meta_window_menu_show (gulong xwindow, if (n_workspaces > 0 && current_workspace >= 0) { + GtkWidget *mi; + + mi = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + gtk_widget_show (mi); + i = 0; while (i < n_workspaces) { char *label; - GtkWidget *mi; MenuData *md; label = g_strdup_printf (_("Move to workspace _%d\n"), @@ -322,12 +333,12 @@ wmspec_change_state (gboolean add, GdkAtom state2) { XEvent xev; - Atom op; + gulong op; if (add) - op = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE); + op = _NET_WM_STATE_ADD; else - op = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE); + op = _NET_WM_STATE_REMOVE; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; @@ -381,21 +392,33 @@ activate_cb (GtkWidget *menuitem, gpointer data) 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: - gdk_error_trap_push (); - gdk_window_maximize (md->window); - gdk_flush (); - gdk_error_trap_pop (); + 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; diff --git a/src/uislave/menu.c b/src/uislave/menu.c index 5e77abc97..f9687a79b 100644 --- a/src/uislave/menu.c +++ b/src/uislave/menu.c @@ -24,6 +24,10 @@ #include #include +#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; @@ -48,7 +52,9 @@ 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_SHADE, NULL, N_("_Shade") } + { META_MESSAGE_MENU_UNMAXIMIZE, NULL, N_("_Unmaximize") }, + { META_MESSAGE_MENU_SHADE, NULL, N_("_Shade") }, + { META_MESSAGE_MENU_UNSHADE, NULL, N_("U_nshade") } }; static void @@ -218,11 +224,16 @@ meta_window_menu_show (gulong xwindow, if (n_workspaces > 0 && current_workspace >= 0) { + GtkWidget *mi; + + mi = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + gtk_widget_show (mi); + i = 0; while (i < n_workspaces) { char *label; - GtkWidget *mi; MenuData *md; label = g_strdup_printf (_("Move to workspace _%d\n"), @@ -322,12 +333,12 @@ wmspec_change_state (gboolean add, GdkAtom state2) { XEvent xev; - Atom op; + gulong op; if (add) - op = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE); + op = _NET_WM_STATE_ADD; else - op = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE); + op = _NET_WM_STATE_REMOVE; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; @@ -381,21 +392,33 @@ activate_cb (GtkWidget *menuitem, gpointer data) 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: - gdk_error_trap_push (); - gdk_window_maximize (md->window); - gdk_flush (); - gdk_error_trap_pop (); + 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; diff --git a/src/uislave/messages.h b/src/uislave/messages.h index c4fe64c06..152038642 100644 --- a/src/uislave/messages.h +++ b/src/uislave/messages.h @@ -132,14 +132,11 @@ typedef enum { META_MESSAGE_MENU_DELETE = 1 << 0, META_MESSAGE_MENU_MINIMIZE = 1 << 1, - META_MESSAGE_MENU_MAXIMIZE = 1 << 2, - META_MESSAGE_MENU_SHADE = 1 << 3, - META_MESSAGE_MENU_WORKSPACES = 1 << 4, - META_MESSAGE_MENU_ALL = META_MESSAGE_MENU_DELETE | - META_MESSAGE_MENU_MINIMIZE | - META_MESSAGE_MENU_MAXIMIZE | - META_MESSAGE_MENU_SHADE | - META_MESSAGE_MENU_WORKSPACES + 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_WORKSPACES = 1 << 6 } MetaMessageWindowMenuOps; struct _MetaMessageShowWindowMenu diff --git a/src/window.c b/src/window.c index f0ed4dd06..59f4af574 100644 --- a/src/window.c +++ b/src/window.c @@ -723,6 +723,119 @@ meta_window_property_notify (MetaWindow *window, return process_property_notify (window, &event->xproperty); } +gboolean +meta_window_client_message (MetaWindow *window, + XEvent *event) +{ + MetaDisplay *display; + + display = window->display; + + 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); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom_net_wm_desktop) + { + int space; + MetaWorkspace *workspace; + + space = event->xclient.data.l[0]; + + meta_verbose ("Request to move %s to screen workspace %d\n", + window->desc, space); + + workspace = + meta_display_get_workspace_by_screen_index (display, + window->screen, + space); + + if (workspace) + meta_window_change_workspace (window, workspace); + else + meta_verbose ("No such workspace %d for screen\n", space); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom_net_wm_state) + { + gulong action; + Atom first; + Atom second; + + action = event->xclient.data.l[0]; + first = event->xclient.data.l[1]; + second = event->xclient.data.l[2]; + + if (meta_is_verbose ()) + { + char *str1; + char *str2; + + meta_error_trap_push (display); + str1 = XGetAtomName (display->xdisplay, first); + if (meta_error_trap_pop (display)) + str1 = NULL; + + meta_error_trap_push (display); + str2 = XGetAtomName (display->xdisplay, second); + if (meta_error_trap_pop (display)) + str2 = NULL; + + meta_verbose ("Request to change _NET_WM_STATE action %ld atom1: %s atom2: %s\n", + action, + str1 ? str1 : "(unknown)", + str2 ? str2 : "(unknown)"); + + if (str1) + XFree (str1); + if (str2) + XFree (str2); + } + + if (first == display->atom_net_wm_state_shaded || + second == display->atom_net_wm_state_shaded) + { + gboolean shade; + + shade = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->shaded)); + if (shade) + meta_window_shade (window); + else + meta_window_unshade (window); + } + + if (first == display->atom_net_wm_state_maximized_horz || + second == display->atom_net_wm_state_maximized_horz || + first == display->atom_net_wm_state_maximized_vert || + second == display->atom_net_wm_state_maximized_vert) + { + gboolean max; + + max = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->maximized)); + if (max) + meta_window_maximize (window); + else + meta_window_unmaximize (window); + } + + return TRUE; + } + + return FALSE; +} + static gboolean process_property_notify (MetaWindow *window, XPropertyEvent *event) diff --git a/src/window.h b/src/window.h index 36a27ad1e..fdce20e3a 100644 --- a/src/window.h +++ b/src/window.h @@ -144,9 +144,6 @@ gboolean meta_window_configure_request (MetaWindow *window, XEvent *event); gboolean meta_window_property_notify (MetaWindow *window, XEvent *event); - - - - - +gboolean meta_window_client_message (MetaWindow *window, + XEvent *event); #endif