This commit is contained in:
rhp 2001-06-06 04:47:37 +00:00
parent ad6efc61b5
commit 0f5fdeb1b1
18 changed files with 1238 additions and 163 deletions

View File

@ -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

View File

@ -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,9 +106,13 @@ 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;
while (i < ScreenCount (xdisplay))
@ -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;
@ -291,6 +299,10 @@ meta_display_ungrab (MetaDisplay *display)
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;
}

View File

@ -30,8 +30,9 @@
typedef struct _MetaDisplay MetaDisplay;
typedef struct _MetaFrame MetaFrame;
typedef struct _MetaScreen MetaScreen;
typedef struct _MetaWindow MetaWindow;
typedef struct _MetaUISlave MetaUISlave;
typedef struct _MetaWindow MetaWindow;
typedef struct _MetaWorkspace MetaWorkspace;
struct _MetaDisplay
{
@ -42,12 +43,15 @@ 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;
GSList *screens;
@ -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

View File

@ -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,10 +219,12 @@ 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,
@ -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,11 +520,112 @@ 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;
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,
@ -526,35 +634,109 @@ frame_get_control (MetaFrame *frame,
}
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,64 +787,93 @@ 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)
{
int x, y;
frame_query_root_pointer (frame, &x, &y);
if (frame->grab)
{
switch (frame->grab->action)
{
case META_FRAME_ACTION_MOVING:
update_move (frame);
update_move (frame, x, y);
break;
case META_FRAME_ACTION_RESIZING_SE:
update_resize_se (frame);
update_resize_se (frame, x, y);
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;
}
}
else
{
update_current_control (frame, x, y);
}
}
break;
case EnterNotify:
/* We handle it here if a decorated window
@ -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;

View File

@ -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 */
@ -49,22 +52,17 @@ 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);

172
src/keybindings.c Normal file
View File

@ -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 <X11/keysym.h>
/* 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 */
}
}

37
src/keybindings.h Normal file
View File

@ -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

View File

@ -26,6 +26,8 @@
#include "colors.h"
#include "uislave.h"
#include "frame.h"
#include "workspace.h"
#include "keybindings.h"
#include <X11/cursorfont.h>
#include <locale.h>
@ -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;
}
}

View File

@ -39,6 +39,8 @@ struct _MetaScreen
MetaThemeEngine *engine;
MetaUISlave *uislave;
MetaWorkspace *active_workspace;
XVisualInfo visual_info;
MetaUIColors colors;
@ -47,6 +49,8 @@ struct _MetaScreen
*/
GC scratch_gc;
guint showing_tooltip : 1;
/*< private >*/
/* we only need one since we only draw to a single visual (that of
@ -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

View File

@ -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 */
@ -115,6 +117,21 @@ default_acquire_frame (MetaFrameInfo *info)
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,
&color);
@ -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,
@ -484,6 +592,8 @@ default_expose_frame (MetaFrameInfo *info,
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)
{
int layout_y;
@ -645,6 +755,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
};

View File

@ -77,6 +77,9 @@ struct _MetaFrameInfo
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;

View File

@ -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);
}

View File

@ -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

View File

@ -64,6 +64,10 @@ message_callback (MetaMessageQueue *mq,
message->show_tip.markup);
break;
case MetaMessageHideTipCode:
meta_fixed_tip_hide ();
break;
default:
meta_ui_warning ("Unhandled message code %d\n",
message->header.message_code);

View File

@ -23,6 +23,8 @@
#include "util.h"
#include "frame.h"
#include "errors.h"
#include "workspace.h"
#include <X11/Xatom.h>
static void constrain_size (MetaWindow *window,
@ -34,11 +36,20 @@ 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 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,8 +180,27 @@ 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);
meta_window_destroy_frame (window);
@ -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,

View File

@ -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;
@ -78,17 +79,24 @@ struct _MetaWindow
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_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,

141
src/workspace.c Normal file
View File

@ -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");
}

48
src/workspace.h Normal file
View File

@ -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