diff --git a/src/Makefile.am b/src/Makefile.am index 9f4f4f264..065efc661 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,6 +49,8 @@ metacity_SOURCES= \ eventqueue.h \ frame.c \ frame.h \ + keybindings.c \ + keybindings.h \ main.c \ main.h \ screen.c \ @@ -61,6 +63,8 @@ metacity_SOURCES= \ util.h \ window.c \ window.h \ + workspace.c \ + workspace.h \ $(copied_sources) bin_PROGRAMS=metacity diff --git a/src/display.c b/src/display.c index 19e88e402..87a3bfb4c 100644 --- a/src/display.c +++ b/src/display.c @@ -26,6 +26,8 @@ #include "window.h" #include "frame.h" #include "errors.h" +#include "keybindings.h" +#include "workspace.h" static GSList *all_displays = NULL; static void meta_spew_event (MetaDisplay *display, @@ -75,7 +77,8 @@ meta_display_open (const char *name) "_NET_WM_NAME", "WM_PROTOCOLS", "WM_TAKE_FOCUS", - "WM_DELETE_WINDOW" + "WM_DELETE_WINDOW", + "WM_STATE" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -103,8 +106,12 @@ meta_display_open (const char *name) display->xdisplay = xdisplay; display->error_traps = NULL; + display->workspaces = NULL; + /* we have to go ahead and do this so error handlers work */ all_displays = g_slist_prepend (all_displays, display); + + meta_display_init_keys (display); screens = NULL; i = 0; @@ -147,6 +154,7 @@ meta_display_open (const char *name) display->atom_wm_protocols = atoms[1]; display->atom_wm_take_focus = atoms[2]; display->atom_wm_delete_window = atoms[3]; + display->atom_wm_state = atoms[4]; /* Now manage all existing windows */ tmp = display->screens; @@ -287,10 +295,14 @@ meta_display_ungrab (MetaDisplay *display) { if (display->server_grab_count == 0) meta_bug ("Ungrabbed non-grabbed server\n"); - + display->server_grab_count -= 1; if (display->server_grab_count == 0) { + /* FIXME we want to purge all pending "queued" stuff + * at this point, such as window hide/show + */ + XUngrabServer (display->xdisplay); } XSync (display->xdisplay, False); @@ -355,6 +367,7 @@ event_queue_callback (MetaEventQueue *queue, switch (event->type) { case KeyPress: + meta_display_process_key_press (display, event); break; case KeyRelease: break; @@ -429,15 +442,6 @@ event_queue_callback (MetaEventQueue *queue, case ReparentNotify: break; case ConfigureNotify: - if (window && event->xconfigure.override_redirect) - { - /* Unmanage it, override_redirect was toggled on? - * Can this happen? - */ - meta_verbose ("Window %s toggled on override redirect\n", - window->desc); - meta_window_free (window); - } break; case ConfigureRequest: /* This comment and code is found in both twm and fvwm */ @@ -755,3 +759,45 @@ meta_display_unregister_x_window (MetaDisplay *display, g_hash_table_remove (display->window_ids, &xwindow); } + +MetaWorkspace* +meta_display_get_workspace_by_index (MetaDisplay *display, + int index) +{ + GList *tmp; + + tmp = g_list_nth (display->workspaces, index); + + if (tmp == NULL) + return NULL; + else + return tmp->data; +} + +MetaWorkspace* +meta_display_get_workspace_by_screen_index (MetaDisplay *display, + MetaScreen *screen, + int index) +{ + GList *tmp; + int i; + + i = 0; + tmp = display->workspaces; + while (tmp != NULL) + { + MetaWorkspace *w = tmp->data; + + if (w->screen == screen) + { + if (i == index) + return w; + else + ++i; + } + + tmp = tmp->next; + } + + return NULL; +} diff --git a/src/display.h b/src/display.h index 8933d1647..6f0925764 100644 --- a/src/display.h +++ b/src/display.h @@ -27,11 +27,12 @@ #include #include "eventqueue.h" -typedef struct _MetaDisplay MetaDisplay; -typedef struct _MetaFrame MetaFrame; -typedef struct _MetaScreen MetaScreen; -typedef struct _MetaWindow MetaWindow; -typedef struct _MetaUISlave MetaUISlave; +typedef struct _MetaDisplay MetaDisplay; +typedef struct _MetaFrame MetaFrame; +typedef struct _MetaScreen MetaScreen; +typedef struct _MetaUISlave MetaUISlave; +typedef struct _MetaWindow MetaWindow; +typedef struct _MetaWorkspace MetaWorkspace; struct _MetaDisplay { @@ -42,11 +43,14 @@ struct _MetaDisplay Atom atom_wm_protocols; Atom atom_wm_take_focus; Atom atom_wm_delete_window; - + Atom atom_wm_state; + /* This is the actual window from focus events, * not the one we last set */ MetaWindow *focus_window; + + GList *workspaces; /*< private-ish >*/ MetaEventQueue *events; @@ -82,4 +86,11 @@ void meta_display_unregister_x_window (MetaDisplay *display, MetaDisplay* meta_display_for_x_display (Display *xdisplay); GSList* meta_displays_list (void); +MetaWorkspace* meta_display_get_workspace_by_index (MetaDisplay *display, + int index); +MetaWorkspace* meta_display_get_workspace_by_screen_index (MetaDisplay *display, + MetaScreen *screen, + int index); + + #endif diff --git a/src/frame.c b/src/frame.c index 92da35fa0..32e607d16 100644 --- a/src/frame.c +++ b/src/frame.c @@ -24,6 +24,19 @@ #include "uislave.h" #include "colors.h" +struct _MetaFrameActionGrab +{ + MetaFrameAction action; + /* initial mouse position for drags */ + int start_root_x, start_root_y; + /* initial window size or initial window position for drags */ + int start_window_x, start_window_y; + /* button doing the dragging */ + int start_button; +}; + +static void clear_tip (MetaFrame *frame); + static void meta_frame_init_info (MetaFrame *frame, MetaFrameInfo *info) @@ -47,6 +60,11 @@ meta_frame_init_info (MetaFrame *frame, info->width = frame->rect.width; info->height = frame->rect.height; info->colors = &(frame->window->screen->colors); + info->current_control = frame->current_control; + if (frame->grab) + info->current_control_state = META_STATE_ACTIVE; + else + info->current_control_state = META_STATE_PRELIGHT; } static void @@ -201,11 +219,13 @@ meta_window_ensure_frame (MetaWindow *window) frame = g_new (MetaFrame, 1); - /* Fill in values that calc_geometry will use */ frame->window = window; frame->xwindow = None; frame->theme_acquired = FALSE; - + frame->grab = NULL; + frame->current_control = META_FRAME_CONTROL_NONE; + frame->tooltip_timeout = 0; + /* This fills in frame->rect as well. */ meta_frame_calc_geometry (frame, window->rect.width, @@ -226,7 +246,10 @@ meta_window_ensure_frame (MetaWindow *window) attrs.background_pixel = frame->bg_pixel; attrs.event_mask = StructureNotifyMask | SubstructureNotifyMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask | + /* We need OwnerGrabButtonMask because during a button + * press we may need to transfer control to the UI slave. + */ + ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask | PointerMotionMask | PointerMotionHintMask | EnterWindowMask | LeaveWindowMask; @@ -245,8 +268,6 @@ meta_window_ensure_frame (MetaWindow *window) meta_verbose ("Frame is 0x%lx\n", frame->xwindow); - frame->action = META_FRAME_ACTION_NONE; - meta_display_register_x_window (window->display, &frame->xwindow, window); /* Reparent the client window; it may be destroyed, @@ -277,10 +298,7 @@ meta_window_ensure_frame (MetaWindow *window) window->frame = frame; /* Put our state back where it should be */ - if (window->iconic) - meta_window_hide (window); - else - meta_window_show (window); + meta_window_queue_calc_showing (window); /* Ungrab server */ meta_display_ungrab (window->display); @@ -297,6 +315,9 @@ meta_window_destroy_frame (MetaWindow *window) frame = window->frame; + if (frame->tooltip_timeout) + clear_tip (frame); + if (frame->theme_data) { meta_frame_init_info (frame, &info); @@ -330,23 +351,7 @@ meta_window_destroy_frame (MetaWindow *window) g_free (frame); /* Put our state back where it should be */ - if (window->iconic) - meta_window_hide (window); - else - meta_window_show (window); -} - -void -meta_frame_move (MetaFrame *frame, - int root_x, - int root_y) -{ - frame->rect.x = root_x; - frame->rect.y = root_y; - - XMoveWindow (frame->window->display->xdisplay, - frame->xwindow, - root_x, root_y); + meta_window_queue_calc_showing (window); } /* Just a chunk of process_configure_event in window.c, @@ -414,6 +419,8 @@ meta_frame_recalc_now (MetaFrame *frame) frame->window->desc, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->child_x, frame->child_y); + + meta_frame_queue_draw (frame); } void @@ -513,48 +520,223 @@ frame_query_root_pointer (MetaFrame *frame, *y = root_y_return; } +static void +show_tip_now (MetaFrame *frame) +{ + const char *tiptext; + + tiptext = NULL; + switch (frame->current_control) + { + case META_FRAME_CONTROL_TITLE: + break; + case META_FRAME_CONTROL_DELETE: + tiptext = _("Close Window"); + break; + case META_FRAME_CONTROL_MENU: + tiptext = _("Menu"); + break; + case META_FRAME_CONTROL_ICONIFY: + tiptext = _("Minimize Window"); + break; + case META_FRAME_CONTROL_MAXIMIZE: + tiptext = _("Maximize Window"); + break; + case META_FRAME_CONTROL_RESIZE_SE: + break; + case META_FRAME_CONTROL_RESIZE_S: + break; + case META_FRAME_CONTROL_RESIZE_SW: + break; + case META_FRAME_CONTROL_RESIZE_N: + break; + case META_FRAME_CONTROL_RESIZE_NE: + break; + case META_FRAME_CONTROL_RESIZE_NW: + break; + case META_FRAME_CONTROL_RESIZE_W: + break; + case META_FRAME_CONTROL_RESIZE_E: + break; + case META_FRAME_CONTROL_NONE: + break; + } + + if (tiptext) + { + int x, y, width, height; + MetaFrameInfo info; + + meta_frame_init_info (frame, &info); + frame->window->screen->engine->get_control_rect (&info, + frame->current_control, + &x, &y, &width, &height, + frame->theme_data); + + /* Display tip a couple pixels below control */ + meta_screen_show_tip (frame->window->screen, + frame->rect.x + x, + frame->rect.y + y + height + 2, + tiptext); + } +} + +static gboolean +tip_timeout_func (gpointer data) +{ + MetaFrame *frame; + + frame = data; + + show_tip_now (frame); + + return FALSE; +} + +#define TIP_DELAY 250 +static void +queue_tip (MetaFrame *frame) +{ + if (frame->tooltip_timeout) + g_source_remove (frame->tooltip_timeout); + + frame->tooltip_timeout = g_timeout_add (250, + tip_timeout_func, + frame); +} + +static void +clear_tip (MetaFrame *frame) +{ + if (frame->tooltip_timeout) + { + g_source_remove (frame->tooltip_timeout); + frame->tooltip_timeout = 0; + } + meta_screen_hide_tip (frame->window->screen); +} + static MetaFrameControl frame_get_control (MetaFrame *frame, int x, int y) { MetaFrameInfo info; - meta_frame_init_info (frame, &info); + if (x < 0 || y < 0 || + x > frame->rect.width || y > frame->rect.height) + return META_FRAME_CONTROL_NONE; + + meta_frame_init_info (frame, &info); + return frame->window->screen->engine->get_control (&info, x, y, frame->theme_data); } static void -update_move (MetaFrame *frame) +update_move (MetaFrame *frame, + int x, + int y) { - int x, y; int dx, dy; - frame_query_root_pointer (frame, &x, &y); + dx = x - frame->grab->start_root_x; + dy = y - frame->grab->start_root_y; - dx = x - frame->start_root_x; - dy = y - frame->start_root_y; - - meta_frame_move (frame, - frame->start_window_x + dx, - frame->start_window_y + dy); + meta_window_move (frame->window, + frame->grab->start_window_x + dx, + frame->grab->start_window_y + dy); } static void -update_resize_se (MetaFrame *frame) +update_resize_se (MetaFrame *frame, + int x, int y) { - int x, y; int dx, dy; - frame_query_root_pointer (frame, &x, &y); - - dx = x - frame->start_root_x; - dy = y - frame->start_root_y; + dx = x - frame->grab->start_root_x; + dy = y - frame->grab->start_root_y; meta_window_resize (frame->window, - frame->start_window_x + dx, - frame->start_window_y + dy); + frame->grab->start_window_x + dx, + frame->grab->start_window_y + dy); +} + +static void +update_current_control (MetaFrame *frame, + int x_root, int y_root) +{ + MetaFrameControl old; + + if (frame->grab) + return; + + old = frame->current_control; + + frame->current_control = frame_get_control (frame, + x_root - frame->rect.x, + y_root - frame->rect.y); + + if (old != frame->current_control) + { + meta_frame_queue_draw (frame); + + if (frame->current_control == META_FRAME_CONTROL_NONE) + clear_tip (frame); + else + queue_tip (frame); + } +} + +static void +grab_action (MetaFrame *frame, + MetaFrameAction action, + Time time) +{ + meta_verbose ("Grabbing action %d\n", action); + + frame->grab = g_new0 (MetaFrameActionGrab, 1); + + if (XGrabPointer (frame->window->display->xdisplay, + frame->xwindow, + False, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | PointerMotionHintMask, + GrabModeAsync, GrabModeAsync, + None, + None, + time) != GrabSuccess) + meta_warning ("Grab for frame action failed\n"); + + frame->grab->action = action; + + /* display ACTIVE state */ + meta_frame_queue_draw (frame); + + clear_tip (frame); +} + +static void +ungrab_action (MetaFrame *frame, + Time time) +{ + int x, y; + + meta_verbose ("Ungrabbing action %d\n", frame->grab->action); + + XUngrabPointer (frame->window->display->xdisplay, + time); + + g_free (frame->grab); + frame->grab = NULL; + + frame_query_root_pointer (frame, &x, &y); + update_current_control (frame, x, y); + + /* undisplay ACTIVE state */ + meta_frame_queue_draw (frame); + + queue_tip (frame); } gboolean @@ -568,12 +750,18 @@ meta_frame_event (MetaFrame *frame, case KeyRelease: break; case ButtonPress: - if (frame->action == META_FRAME_ACTION_NONE) + /* you can use button 2 to move a window without raising it */ + if (event->xbutton.button == 1) + meta_window_raise (frame->window); + + update_current_control (frame, + event->xbutton.x_root, + event->xbutton.y_root); + + if (frame->grab == NULL) { MetaFrameControl control; - control = frame_get_control (frame, - event->xbutton.x, - event->xbutton.y); + control = frame->current_control; if (((control == META_FRAME_CONTROL_TITLE || control == META_FRAME_CONTROL_NONE) && @@ -582,12 +770,16 @@ meta_frame_event (MetaFrame *frame, { meta_verbose ("Begin move on %s\n", frame->window->desc); - frame->action = META_FRAME_ACTION_MOVING; - frame->start_root_x = event->xbutton.x_root; - frame->start_root_y = event->xbutton.y_root; - frame->start_window_x = frame->rect.x; - frame->start_window_y = frame->rect.y; - frame->start_button = event->xbutton.button; + grab_action (frame, META_FRAME_ACTION_MOVING, + event->xbutton.time); + frame->grab->start_root_x = event->xbutton.x_root; + frame->grab->start_root_y = event->xbutton.y_root; + /* pos of client in root coords */ + frame->grab->start_window_x = + frame->rect.x + frame->window->rect.x; + frame->grab->start_window_y = + frame->rect.y + frame->window->rect.y; + frame->grab->start_button = event->xbutton.button; } else if (control == META_FRAME_CONTROL_DELETE && event->xbutton.button == 1) @@ -595,63 +787,92 @@ meta_frame_event (MetaFrame *frame, /* FIXME delete event */ meta_verbose ("Close control clicked on %s\n", frame->window->desc); - meta_window_delete (frame->window, event->xbutton.time); + grab_action (frame, META_FRAME_ACTION_DELETING, + event->xbutton.time); + frame->grab->start_button = event->xbutton.button; } else if (control == META_FRAME_CONTROL_RESIZE_SE && event->xbutton.button == 1) { meta_verbose ("Resize control clicked on %s\n", frame->window->desc); - frame->action = META_FRAME_ACTION_RESIZING_SE; - frame->start_root_x = event->xbutton.x_root; - frame->start_root_y = event->xbutton.y_root; - frame->start_window_x = frame->window->rect.width; - frame->start_window_y = frame->window->rect.height; - frame->start_button = event->xbutton.button; + grab_action (frame, META_FRAME_ACTION_RESIZING_SE, + event->xbutton.time); + frame->grab->start_root_x = event->xbutton.x_root; + frame->grab->start_root_y = event->xbutton.y_root; + frame->grab->start_window_x = frame->window->rect.width; + frame->grab->start_window_y = frame->window->rect.height; + frame->grab->start_button = event->xbutton.button; } } break; case ButtonRelease: - if (event->xbutton.button == frame->start_button) + if (frame->grab) + meta_debug_spew ("Here! grab %p action %d buttons %d %d\n", + frame->grab, frame->grab->action, frame->grab->start_button, event->xbutton.button); + if (frame->grab && + event->xbutton.button == frame->grab->start_button) { - switch (frame->action) + switch (frame->grab->action) { case META_FRAME_ACTION_MOVING: - update_move (frame); + update_move (frame, event->xbutton.x_root, event->xbutton.y_root); + ungrab_action (frame, event->xbutton.time); + update_current_control (frame, + event->xbutton.x_root, event->xbutton.y_root); break; case META_FRAME_ACTION_RESIZING_SE: - update_resize_se (frame); + update_resize_se (frame, event->xbutton.x_root, event->xbutton.y_root); + ungrab_action (frame, event->xbutton.time); + update_current_control (frame, + event->xbutton.x_root, event->xbutton.y_root); + break; + + case META_FRAME_ACTION_DELETING: + /* 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_DELETE) + meta_window_delete (frame->window, event->xbutton.time); break; - default: + meta_warning ("Unhandled action in button release\n"); break; } - - frame->action = META_FRAME_ACTION_NONE; } break; case MotionNotify: - switch (frame->action) - { - case META_FRAME_ACTION_MOVING: - update_move (frame); - break; + { + int x, y; - case META_FRAME_ACTION_RESIZING_SE: - update_resize_se (frame); - break; - - case META_FRAME_ACTION_NONE: -#if 0 - meta_ui_slave_show_tip (frame->window->screen->uislave, - frame->rect.x, - frame->rect.y, - "Hi this is a tooltip"); -#endif - break; - default: - break; + frame_query_root_pointer (frame, &x, &y); + if (frame->grab) + { + switch (frame->grab->action) + { + case META_FRAME_ACTION_MOVING: + update_move (frame, x, y); + break; + + case META_FRAME_ACTION_RESIZING_SE: + update_resize_se (frame, x, y); + break; + + case META_FRAME_ACTION_NONE: + + break; + default: + break; + } + } + else + { + update_current_control (frame, x, y); + } } break; case EnterNotify: @@ -663,6 +884,7 @@ meta_frame_event (MetaFrame *frame, event->xcrossing.time); break; case LeaveNotify: + update_current_control (frame, -1, -1); break; case FocusIn: break; @@ -698,10 +920,12 @@ meta_frame_event (MetaFrame *frame, } break; case UnmapNotify: - frame->action = META_FRAME_ACTION_NONE; + if (frame->grab) + ungrab_action (frame, CurrentTime); break; case MapNotify: - frame->action = META_FRAME_ACTION_NONE; + if (frame->grab) + ungrab_action (frame, CurrentTime); break; case MapRequest: break; diff --git a/src/frame.h b/src/frame.h index 0757d7a0c..0b5f2a08e 100644 --- a/src/frame.h +++ b/src/frame.h @@ -28,9 +28,12 @@ typedef enum { META_FRAME_ACTION_NONE, META_FRAME_ACTION_MOVING, + META_FRAME_ACTION_DELETING, META_FRAME_ACTION_RESIZING_SE } MetaFrameAction; +typedef struct _MetaFrameActionGrab MetaFrameActionGrab; + struct _MetaFrame { /* window we frame */ @@ -48,23 +51,18 @@ struct _MetaFrame gpointer theme_data; gulong bg_pixel; - - MetaFrameAction action; - /* initial mouse position for drags */ - int start_root_x, start_root_y; - /* initial window size or initial window position for drags */ - int start_window_x, start_window_y; - /* button doing the dragging */ - int start_button; + MetaFrameActionGrab *grab; + + MetaFrameControl current_control; + + guint tooltip_timeout; + guint theme_acquired : 1; }; void meta_window_ensure_frame (MetaWindow *window); void meta_window_destroy_frame (MetaWindow *window); -void meta_frame_move (MetaFrame *frame, - int root_x, - int root_y); void meta_frame_child_configure_request (MetaFrame *frame); void meta_frame_recalc_now (MetaFrame *frame); void meta_frame_queue_recalc (MetaFrame *frame); diff --git a/src/keybindings.c b/src/keybindings.c new file mode 100644 index 000000000..56ab3646a --- /dev/null +++ b/src/keybindings.c @@ -0,0 +1,172 @@ +/* Metacity Keybindings */ + +/* + * 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 "keybindings.h" +#include "workspace.h" +#include "errors.h" + +#include + +/* Plainly we'll want some more configurable keybinding system + * eventually. + */ + +typedef void (* MetaKeyHandler) (MetaDisplay *display, + XEvent *event, + gpointer data); + +static void handle_activate_workspace (MetaDisplay *display, + XEvent *event, + gpointer data); + +typedef struct _MetaKeyBinding MetaKeyBinding; + +struct _MetaKeyBinding +{ + KeySym keysym; + gulong mask; + MetaKeyHandler handler; + gpointer data; + int keycode; +}; + +#define INTERESTING_MODIFIERS (ShiftMask | ControlMask | Mod1Mask) + +static MetaKeyBinding bindings[] = { + { XK_F1, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (0), 0 }, + { XK_F2, Mod1Mask, handle_activate_workspace, GINT_TO_POINTER (1), 0 } +}; + +void +meta_display_init_keys (MetaDisplay *display) +{ + int i; + + i = 0; + while (i < G_N_ELEMENTS (bindings)) + { + bindings[i].keycode = XKeysymToKeycode (display->xdisplay, + bindings[i].keysym); + + ++i; + } +} + +void +meta_screen_grab_keys (MetaScreen *screen) +{ + int i; + + i = 0; + while (i < G_N_ELEMENTS (bindings)) + { + if (bindings[i].keycode != 0) + { + int result; + + meta_error_trap_push (screen->display); + XGrabKey (screen->display->xdisplay, bindings[i].keycode, + bindings[i].mask, screen->xroot, True, + GrabModeAsync, GrabModeAsync); + result = meta_error_trap_pop (screen->display); + if (result != Success) + { + const char *name; + + name = XKeysymToString (bindings[i].keysym); + if (name == NULL) + name = "(unknown)"; + + if (result == BadAccess) + meta_warning (_("Some other program is already using the key %s as a binding\n"), name); + else + meta_bug ("Unexpected error setting up keybindings\n"); + } + } + + ++i; + } +} + +void +meta_screen_ungrab_keys (MetaScreen *screen) +{ + int i; + + i = 0; + while (i < G_N_ELEMENTS (bindings)) + { + if (bindings[i].keycode != 0) + { + XUngrabKey (screen->display->xdisplay, bindings[i].keycode, + bindings[i].mask, screen->xroot); + } + + ++i; + } +} + +void +meta_display_process_key_press (MetaDisplay *display, + XEvent *event) +{ + KeySym keysym; + int i; + + keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0); + + i = 0; + while (i < G_N_ELEMENTS (bindings)) + { + if (bindings[i].keysym == keysym && + ((event->xkey.state & INTERESTING_MODIFIERS) == + bindings[i].mask)) + { + (* bindings[i].handler) (display, event, bindings[i].data); + break; + } + + ++i; + } +} + +static void +handle_activate_workspace (MetaDisplay *display, + XEvent *event, + gpointer data) +{ + int which; + MetaWorkspace *workspace; + + which = GPOINTER_TO_INT (data); + + workspace = meta_display_get_workspace_by_index (display, which); + + if (workspace) + { + meta_workspace_activate (workspace); + } + else + { + /* We could offer to create it I suppose */ + } +} + diff --git a/src/keybindings.h b/src/keybindings.h new file mode 100644 index 000000000..9f252f096 --- /dev/null +++ b/src/keybindings.h @@ -0,0 +1,37 @@ +/* Metacity Keybindings */ + +/* + * 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_KEYBINDINGS_H +#define META_KEYBINDINGS_H + +#include "display.h" + +void meta_display_init_keys (MetaDisplay *display); +void meta_screen_grab_keys (MetaScreen *screen); +void meta_screen_ungrab_keys (MetaScreen *screen); +void meta_display_process_key_press (MetaDisplay *display, + XEvent *event); + +#endif + + + + diff --git a/src/screen.c b/src/screen.c index f47e650e3..b79b44b29 100644 --- a/src/screen.c +++ b/src/screen.c @@ -26,6 +26,8 @@ #include "colors.h" #include "uislave.h" #include "frame.h" +#include "workspace.h" +#include "keybindings.h" #include #include @@ -100,9 +102,20 @@ meta_screen_new (MetaDisplay *display, screen->engine = &meta_default_engine; + screen->showing_tooltip = FALSE; + + /* Screens must have at least one workspace at all times, + * so create that required workspace. + */ + screen->active_workspace = meta_workspace_new (screen); + /* FIXME, for debugging create another one. */ + meta_workspace_new (screen); + meta_screen_init_visual_info (screen); meta_screen_init_ui_colors (screen); + meta_screen_grab_keys (screen); + screen->scratch_gc = XCreateGC (screen->display->xdisplay, screen->xroot, 0, @@ -121,6 +134,8 @@ meta_screen_new (MetaDisplay *display, void meta_screen_free (MetaScreen *screen) { + meta_screen_ungrab_keys (screen); + meta_ui_slave_free (screen->uislave); XFreeGC (screen->display->xdisplay, @@ -419,3 +434,25 @@ meta_screen_queue_frame_redraws (MetaScreen *screen) { meta_screen_foreach_window (screen, queue_draw, NULL); } + + +void +meta_screen_show_tip (MetaScreen *screen, + int root_x, + int root_y, + const char *markup) +{ + /* even if screen->showing_tip, may change position/text */ + meta_ui_slave_show_tip (screen->uislave, root_x, root_y, markup); + screen->showing_tooltip = TRUE; +} + +void +meta_screen_hide_tip (MetaScreen *screen) +{ + if (screen->showing_tooltip) + { + meta_ui_slave_hide_tip (screen->uislave); + screen->showing_tooltip = FALSE; + } +} diff --git a/src/screen.h b/src/screen.h index 42cca884d..93de5bc22 100644 --- a/src/screen.h +++ b/src/screen.h @@ -39,6 +39,8 @@ struct _MetaScreen MetaThemeEngine *engine; MetaUISlave *uislave; + MetaWorkspace *active_workspace; + XVisualInfo visual_info; MetaUIColors colors; @@ -46,6 +48,8 @@ struct _MetaScreen * left with a clip. */ GC scratch_gc; + + guint showing_tooltip : 1; /*< private >*/ @@ -68,6 +72,12 @@ void meta_screen_foreach_window (MetaScreen *scree gpointer data); void meta_screen_queue_frame_redraws (MetaScreen *screen); +void meta_screen_show_tip (MetaScreen *screen, + int root_x, + int root_y, + const char *markup); + +void meta_screen_hide_tip (MetaScreen *screen); #endif diff --git a/src/theme.c b/src/theme.c index 2db9c513e..700a2e62a 100644 --- a/src/theme.c +++ b/src/theme.c @@ -58,6 +58,8 @@ struct _DefaultScreenData GC black_gc; GC selected_gc; GC selected_text_gc; + GC active_gc; + GC prelight_gc; }; /* FIXME store this on the screen */ @@ -114,6 +116,21 @@ default_acquire_frame (MetaFrameInfo *info) RootWindowOfScreen (info->screen), GCForeground, &vals); + + vals.foreground = meta_get_x_pixel (info->screen, + &info->colors->bg[META_STATE_ACTIVE]); + screen_data->active_gc = XCreateGC (info->display, + RootWindowOfScreen (info->screen), + GCForeground, + &vals); + + vals.foreground = meta_get_x_pixel (info->screen, + &info->colors->bg[META_STATE_PRELIGHT]); + screen_data->prelight_gc = XCreateGC (info->display, + RootWindowOfScreen (info->screen), + GCForeground, + &vals); + color.red = color.green = color.blue = 0; vals.foreground = meta_get_x_pixel (info->screen, @@ -422,6 +439,97 @@ set_clip (Display *display, GC gc, MetaRectangle *rect) } } +static MetaRectangle* +control_rect (MetaFrameControl control, + DefaultFrameGeometry *fgeom) +{ + MetaRectangle *rect; + + rect = NULL; + switch (control) + { + case META_FRAME_CONTROL_TITLE: + rect = &fgeom->title_rect; + break; + case META_FRAME_CONTROL_DELETE: + rect = &fgeom->close_rect; + break; + case META_FRAME_CONTROL_MENU: + rect = &fgeom->menu_rect; + break; + case META_FRAME_CONTROL_ICONIFY: + rect = &fgeom->min_rect; + break; + case META_FRAME_CONTROL_MAXIMIZE: + rect = &fgeom->max_rect; + break; + case META_FRAME_CONTROL_RESIZE_SE: + break; + case META_FRAME_CONTROL_RESIZE_S: + break; + case META_FRAME_CONTROL_RESIZE_SW: + break; + case META_FRAME_CONTROL_RESIZE_N: + break; + case META_FRAME_CONTROL_RESIZE_NE: + break; + case META_FRAME_CONTROL_RESIZE_NW: + break; + case META_FRAME_CONTROL_RESIZE_W: + break; + case META_FRAME_CONTROL_RESIZE_E: + break; + case META_FRAME_CONTROL_NONE: + break; + } + + return rect; +} + +static void +draw_current_control_bg (MetaFrameInfo *info, + DefaultFrameGeometry *fgeom) +{ + int xoff, yoff; + MetaRectangle *rect; + + xoff = info->xoffset; + yoff = info->yoffset; + + rect = control_rect (info->current_control, fgeom); + + if (rect == NULL) + return; + + if (info->current_control == META_FRAME_CONTROL_TITLE) + return; + + switch (info->current_control_state) + { + /* FIXME turn this off after testing */ + case META_STATE_PRELIGHT: + XFillRectangle (info->display, + info->drawable, + screen_data->prelight_gc, + xoff + rect->x, + yoff + rect->y, + rect->width, rect->height); + break; + + case META_STATE_ACTIVE: + XFillRectangle (info->display, + info->drawable, + screen_data->active_gc, + xoff + rect->x, + yoff + rect->y, + rect->width, rect->height); + break; + + default: + break; + } +} + static void default_expose_frame (MetaFrameInfo *info, int x, int y, @@ -483,6 +591,8 @@ default_expose_frame (MetaFrameInfo *info, info->width - fgeom.right_width - fgeom.left_width + 1, info->height - fgeom.bottom_height - fgeom.top_height + 1); } + + draw_current_control_bg (info, &fgeom); if (fgeom.title_rect.width > 0 && fgeom.title_rect.height > 0) { @@ -527,7 +637,7 @@ default_expose_frame (MetaFrameInfo *info, } if (fgeom.close_rect.width > 0 && fgeom.close_rect.height > 0) - { + { XDrawLine (info->display, info->drawable, screen_data->fg_gc, @@ -644,6 +754,15 @@ default_get_control (MetaFrameInfo *info, if (POINT_IN_RECT (x, y, fgeom.close_rect)) return META_FRAME_CONTROL_DELETE; + + if (POINT_IN_RECT (x, y, fgeom.min_rect)) + return META_FRAME_CONTROL_ICONIFY; + + if (POINT_IN_RECT (x, y, fgeom.max_rect)) + return META_FRAME_CONTROL_MAXIMIZE; + + if (POINT_IN_RECT (x, y, fgeom.menu_rect)) + return META_FRAME_CONTROL_MENU; if (POINT_IN_RECT (x, y, fgeom.title_rect)) return META_FRAME_CONTROL_TITLE; @@ -655,6 +774,36 @@ default_get_control (MetaFrameInfo *info, return META_FRAME_CONTROL_NONE; } +static void +default_get_control_rect (MetaFrameInfo *info, + MetaFrameControl control, + int *x, int *y, + int *width, int *height, + gpointer frame_data) +{ + MetaRectangle *rect; + DefaultFrameData *d; + DefaultFrameGeometry fgeom; + + d = frame_data; + + calc_geometry (info, d, &fgeom); + + rect = control_rect (control, &fgeom); + + if (rect) + { + *x = rect->x; + *y = rect->y; + *width = rect->width; + *height = rect->height; + } + else + { + *x = *y = *width = *height = 0; + } +} + /* FIXME add this to engine vtable */ static void default_release_screen (Screen *screen) @@ -668,6 +817,8 @@ default_release_screen (Screen *screen) XFreeGC (DisplayOfScreen (screen), screen_data->black_gc); XFreeGC (DisplayOfScreen (screen), screen_data->light_gc); XFreeGC (DisplayOfScreen (screen), screen_data->dark_gc); + XFreeGC (DisplayOfScreen (screen), screen_data->active_gc); + XFreeGC (DisplayOfScreen (screen), screen_data->prelight_gc); } } @@ -677,5 +828,6 @@ MetaThemeEngine meta_default_engine = { default_release_frame, default_fill_frame_geometry, default_expose_frame, - default_get_control + default_get_control, + default_get_control_rect }; diff --git a/src/theme.h b/src/theme.h index 5fdea6dba..5a7a9b93b 100644 --- a/src/theme.h +++ b/src/theme.h @@ -76,6 +76,9 @@ struct _MetaFrameInfo const char *title; const MetaUIColors *colors; + + MetaFrameControl current_control; + MetaUIState current_control_state; /* Equal to child size before fill_frame_geometry * has been called @@ -121,6 +124,12 @@ struct _MetaThemeEngine MetaFrameControl (* get_control) (MetaFrameInfo *info, int x, int y, gpointer frame_data); + + void (* get_control_rect) (MetaFrameInfo *info, + MetaFrameControl control, + int *x, int *y, + int *width, int *height, + gpointer frame_data); }; extern MetaThemeEngine meta_default_engine; diff --git a/src/uislave.c b/src/uislave.c index 994cb599b..680bb1027 100644 --- a/src/uislave.c +++ b/src/uislave.c @@ -305,3 +305,15 @@ meta_ui_slave_show_tip (MetaUISlave *uislave, send_message (uislave, (MetaMessage*)&showtip); } + +void +meta_ui_slave_hide_tip (MetaUISlave *uislave) +{ + MetaMessageHideTip hidetip; + + memset (&hidetip, 0, META_MESSAGE_LENGTH (MetaMessageHideTip)); + hidetip.header.message_code = MetaMessageHideTipCode; + hidetip.header.length = META_MESSAGE_LENGTH (MetaMessageHideTip); + + send_message (uislave, (MetaMessage*)&hidetip); +} diff --git a/src/uislave.h b/src/uislave.h index 09c59dd6f..673901b0f 100644 --- a/src/uislave.h +++ b/src/uislave.h @@ -62,5 +62,6 @@ void meta_ui_slave_show_tip (MetaUISlave *uislave, int root_x, int root_y, const char *markup_text); +void meta_ui_slave_hide_tip (MetaUISlave *uislave); #endif diff --git a/src/uislave/main.c b/src/uislave/main.c index fc4f9ae1e..284fbd214 100644 --- a/src/uislave/main.c +++ b/src/uislave/main.c @@ -63,6 +63,10 @@ message_callback (MetaMessageQueue *mq, message->show_tip.root_y, message->show_tip.markup); break; + + case MetaMessageHideTipCode: + meta_fixed_tip_hide (); + break; default: meta_ui_warning ("Unhandled message code %d\n", diff --git a/src/window.c b/src/window.c index 32037f8f6..4b6a75fda 100644 --- a/src/window.c +++ b/src/window.c @@ -23,22 +23,33 @@ #include "util.h" #include "frame.h" #include "errors.h" +#include "workspace.h" + #include -static void constrain_size (MetaWindow *window, - int width, - int height, - int *new_width, - int *new_height); -static int update_size_hints (MetaWindow *window); -static int update_title (MetaWindow *window); -static int update_protocols (MetaWindow *window); -static int update_wm_hints (MetaWindow *window); -static gboolean process_configure_request (MetaWindow *window, - int x, int y, int width, int height, - int border_width); -static gboolean process_property_notify (MetaWindow *window, - XPropertyEvent *event); +static void constrain_size (MetaWindow *window, + int width, + int height, + int *new_width, + int *new_height); +static int update_size_hints (MetaWindow *window); +static int update_title (MetaWindow *window); +static int update_protocols (MetaWindow *window); +static int update_wm_hints (MetaWindow *window); +static int set_wm_state (MetaWindow *window, + int state); +static void send_configure_notify (MetaWindow *window); +static gboolean process_configure_request (MetaWindow *window, + int x, + int y, + int width, + int height, + int border_width); +static gboolean process_property_notify (MetaWindow *window, + XPropertyEvent *event); +static void meta_window_show (MetaWindow *window); +static void meta_window_hide (MetaWindow *window); + MetaWindow* meta_window_new (MetaDisplay *display, Window xwindow) @@ -88,6 +99,7 @@ meta_window_new (MetaDisplay *display, Window xwindow) * type */ window->display = display; + window->workspaces = NULL; window->screen = NULL; tmp = display->screens; @@ -141,21 +153,26 @@ meta_window_new (MetaDisplay *display, Window xwindow) if (window->initially_iconic) { - /* WM_HINTS said iconic */ - window->iconic = TRUE; + /* WM_HINTS said minimized */ + window->minimized = TRUE; + meta_verbose ("Window %s asked to start out minimized\n", window->desc); } - meta_window_resize (window, window->size_hints.width, window->size_hints.height); + meta_window_resize (window, + window->size_hints.width, + window->size_hints.height); + + /* FIXME we have a tendency to set this then immediately + * change it again. + */ + set_wm_state (window, window->iconic ? IconicState : NormalState); meta_window_ensure_frame (window); - /* Put our state where it should be (ensure_frame also did this - * for decorated windows, but should be harmless to do twice) - */ - if (window->iconic) - meta_window_hide (window); - else - meta_window_show (window); + meta_workspace_add_window (window->screen->active_workspace, window); + + /* Put our state back where it should be */ + meta_window_queue_calc_showing (window); return window; } @@ -163,7 +180,26 @@ meta_window_new (MetaDisplay *display, Window xwindow) void meta_window_free (MetaWindow *window) { + GList *tmp; + meta_verbose ("Unmanaging 0x%lx\n", window->xwindow); + + tmp = window->workspaces; + while (tmp != NULL) + { + GList *next; + + next = tmp->next; + + /* pops front of list */ + meta_workspace_remove_window (tmp->data, window); + + tmp = next; + } + + g_assert (window->workspaces == NULL); + + set_wm_state (window, WithdrawnState); meta_display_unregister_x_window (window->display, window->xwindow); @@ -183,9 +219,64 @@ meta_window_free (MetaWindow *window) g_free (window); } +static int +set_wm_state (MetaWindow *window, + int state) +{ + unsigned long data[1]; + + /* twm sets the icon window as data[1], I couldn't find that in + * ICCCM. + */ + data[0] = state; + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom_wm_state, + window->display->atom_wm_state, + 32, PropModeReplace, (guchar*) data, 1); + return meta_error_trap_pop (window->display); +} + +void +meta_window_calc_showing (MetaWindow *window) +{ + gboolean on_workspace; + + on_workspace = g_list_find (window->workspaces, + window->screen->active_workspace) != NULL; + + if (!on_workspace) + meta_verbose ("Window %s is not on workspace %d\n", + window->desc, + meta_workspace_index (window->screen->active_workspace)); + else + meta_verbose ("Window %s is on the active workspace %d\n", + window->desc, + meta_workspace_index (window->screen->active_workspace)); + + if (window->minimized || !on_workspace) + { + meta_window_hide (window); + } + else + { + meta_window_show (window); + } +} + +void +meta_window_queue_calc_showing (MetaWindow *window) +{ + /* FIXME */ + meta_window_calc_showing (window); +} + void meta_window_show (MetaWindow *window) { + meta_verbose ("Showing window %s\n", window->desc); + if (window->frame) XMapWindow (window->display->xdisplay, window->frame->xwindow); XMapWindow (window->display->xdisplay, window->xwindow); @@ -193,25 +284,33 @@ meta_window_show (MetaWindow *window) /* These flags aren't always in sync, iconic * is set only here in show/hide, mapped * can be set in a couple other places where - * we map/unmap + * we map/unmap. So that's why both flags exist. */ window->mapped = TRUE; - window->iconic = FALSE; - /* FIXME update WM_STATE */ + if (window->iconic) + { + window->iconic = FALSE; + set_wm_state (window, NormalState); + } } void meta_window_hide (MetaWindow *window) { + meta_verbose ("Hiding window %s\n", window->desc); + if (window->frame) XUnmapWindow (window->display->xdisplay, window->frame->xwindow); XUnmapWindow (window->display->xdisplay, window->xwindow); window->mapped = FALSE; - window->iconic = TRUE; - /* FIXME update WM_STATE */ + if (!window->iconic) + { + window->iconic = TRUE; + set_wm_state (window, IconicState); + } } void @@ -259,6 +358,48 @@ meta_window_resize (MetaWindow *window, } } +void +meta_window_move (MetaWindow *window, + int root_x_nw, + int root_y_nw) +{ + if (window->frame) + { + int new_x, new_y; + + new_x = root_x_nw - window->frame->child_x; + new_y = root_y_nw - window->frame->child_y; + + if (new_x != window->frame->rect.x || + new_y != window->frame->rect.y) + { + window->frame->rect.x = new_x; + window->frame->rect.y = new_y; + + XMoveWindow (window->display->xdisplay, + window->frame->xwindow, + window->frame->rect.x, + window->frame->rect.y); + } + } + else + { + if (root_x_nw != window->rect.x || + root_y_nw != window->rect.y) + { + window->rect.x = root_x_nw; + window->rect.y = root_y_nw; + + XMoveWindow (window->display->xdisplay, + window->xwindow, + window->rect.x, + window->rect.y); + } + } + + send_configure_notify (window); +} + void meta_window_delete (MetaWindow *window, Time timestamp) @@ -308,6 +449,26 @@ meta_window_focus (MetaWindow *window, } } +void +meta_window_raise (MetaWindow *window) +{ + meta_verbose ("Raising window %s\n", window->desc); + + if (window->frame == NULL) + { + meta_error_trap_push (window->display); + + XRaiseWindow (window->display->xdisplay, window->xwindow); + + meta_error_trap_pop (window->display); + } + else + { + XRaiseWindow (window->display->xdisplay, + window->frame->xwindow); + } +} + void meta_window_send_icccm_message (MetaWindow *window, Atom atom, diff --git a/src/window.h b/src/window.h index 453318dc3..70c2a11a3 100644 --- a/src/window.h +++ b/src/window.h @@ -30,6 +30,7 @@ struct _MetaWindow { MetaDisplay *display; MetaScreen *screen; + GList *workspaces; Window xwindow; /* may be NULL! not all windows get decorated */ MetaFrame *frame; @@ -51,7 +52,7 @@ struct _MetaWindow */ guint iconic : 1; /* initially_iconic is the WM_HINTS setting when we first manage - * the window. + * the window. It's taken to mean initially minimized. */ guint initially_iconic : 1; @@ -75,20 +76,27 @@ struct _MetaWindow XSizeHints size_hints; }; -MetaWindow* meta_window_new (MetaDisplay *display, - Window xwindow); -void meta_window_free (MetaWindow *window); -void meta_window_show (MetaWindow *window); -void meta_window_hide (MetaWindow *window); -void meta_window_minimize (MetaWindow *window); -void meta_window_unminimize (MetaWindow *window); -void meta_window_resize (MetaWindow *window, - int w, - int h); -void meta_window_delete (MetaWindow *window, - Time timestamp); -void meta_window_focus (MetaWindow *window, - Time timestamp); +MetaWindow* meta_window_new (MetaDisplay *display, + Window xwindow); +void meta_window_free (MetaWindow *window); +void meta_window_calc_showing (MetaWindow *window); +void meta_window_queue_calc_showing (MetaWindow *window); +void meta_window_minimize (MetaWindow *window); +void meta_window_unminimize (MetaWindow *window); +void meta_window_resize (MetaWindow *window, + int w, + int h); + +/* args to move are window pos, not frame pos */ +void meta_window_move (MetaWindow *window, + int root_x_nw, + int root_y_nw); +void meta_window_delete (MetaWindow *window, + Time timestamp); +void meta_window_focus (MetaWindow *window, + Time timestamp); +void meta_window_raise (MetaWindow *window); + /* Sends a client message */ void meta_window_send_icccm_message (MetaWindow *window, diff --git a/src/workspace.c b/src/workspace.c new file mode 100644 index 000000000..d0e2339fd --- /dev/null +++ b/src/workspace.c @@ -0,0 +1,141 @@ +/* Metacity Workspaces */ + +/* + * 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 "workspace.h" + +void meta_workspace_queue_calc_showing (MetaWorkspace *workspace); + +MetaWorkspace* +meta_workspace_new (MetaScreen *screen) +{ + MetaWorkspace *workspace; + + workspace = g_new (MetaWorkspace, 1); + + workspace->screen = screen; + workspace->screen->display->workspaces = + g_list_append (workspace->screen->display->workspaces, workspace); + workspace->windows = NULL; + + return workspace; +} + +void +meta_workspace_free (MetaWorkspace *workspace) +{ + GList *tmp; + + tmp = workspace->windows; + while (tmp != NULL) + { + GList *next; + next = tmp->next; + /* pop front of list */ + meta_workspace_remove_window (workspace, tmp->data); + + tmp = next; + } + + g_assert (workspace->windows == NULL); + + workspace->screen->display->workspaces = + g_list_remove (workspace->screen->display->workspaces, workspace); + + g_free (workspace); +} + +void +meta_workspace_add_window (MetaWorkspace *workspace, + MetaWindow *window) +{ + g_return_if_fail (g_list_find (workspace->windows, window) == NULL); + + workspace->windows = g_list_prepend (workspace->windows, window); + window->workspaces = g_list_prepend (window->workspaces, workspace); + + meta_window_queue_calc_showing (window); +} + +void +meta_workspace_remove_window (MetaWorkspace *workspace, + MetaWindow *window) +{ + g_return_if_fail (g_list_find (workspace->windows, window) != NULL); + + workspace->windows = g_list_remove (workspace->windows, window); + window->workspaces = g_list_remove (window->workspaces, workspace); + + meta_window_queue_calc_showing (window); +} + +void +meta_workspace_queue_calc_showing (MetaWorkspace *workspace) +{ + GList *tmp; + + tmp = workspace->windows; + while (tmp != NULL) + { + meta_window_queue_calc_showing (tmp->data); + + tmp = tmp->next; + } +} + +void +meta_workspace_activate (MetaWorkspace *workspace) +{ + MetaWorkspace *old; + + meta_verbose ("Activating workspace %d\n", + meta_workspace_index (workspace)); + + if (workspace->screen->active_workspace == workspace) + return; + + old = workspace->screen->active_workspace; + + workspace->screen->active_workspace = workspace; + + meta_workspace_queue_calc_showing (old); + meta_workspace_queue_calc_showing (workspace); +} + +int +meta_workspace_index (MetaWorkspace *workspace) +{ + GList *tmp; + int i; + + i = 0; + tmp = workspace->screen->display->workspaces; + while (tmp != NULL) + { + if (tmp->data == workspace) + return i; + + ++i; + + tmp = tmp->next; + } + + meta_bug ("Workspace does not exist to index!\n"); +} diff --git a/src/workspace.h b/src/workspace.h new file mode 100644 index 000000000..dcf808d5b --- /dev/null +++ b/src/workspace.h @@ -0,0 +1,48 @@ +/* Metacity Workspaces */ + +/* + * 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_WORKSPACE_H +#define META_WORKSPACE_H + +#include "window.h" + +struct _MetaWorkspace +{ + MetaScreen *screen; + + GList *windows; +}; + +MetaWorkspace* meta_workspace_new (MetaScreen *screen); +void meta_workspace_free (MetaWorkspace *workspace); +void meta_workspace_add_window (MetaWorkspace *workspace, + MetaWindow *window); +void meta_workspace_remove_window (MetaWorkspace *workspace, + MetaWindow *window); + +void meta_workspace_activate (MetaWorkspace *workspace); +int meta_workspace_index (MetaWorkspace *workspace); + +#endif + + + +