xwm: set appropriate cursors for the frame window
authorTiago Vignatti <tiago.vignatti@intel.com>
Mon, 16 Jul 2012 16:09:19 +0000 (12:09 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Mon, 16 Jul 2012 17:35:27 +0000 (13:35 -0400)
Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
src/xwayland/window-manager.c
src/xwayland/xwayland.h

index 97b2b06..e73e588 100644 (file)
@@ -568,6 +568,9 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
                XCB_EVENT_MASK_KEY_RELEASE |
                XCB_EVENT_MASK_BUTTON_PRESS |
                XCB_EVENT_MASK_BUTTON_RELEASE |
+               XCB_EVENT_MASK_POINTER_MOTION |
+               XCB_EVENT_MASK_ENTER_WINDOW |
+               XCB_EVENT_MASK_LEAVE_WINDOW |
                XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
                XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
 
@@ -923,6 +926,104 @@ weston_wm_handle_client_message(struct weston_wm *wm,
                weston_wm_window_handle_moveresize(window, client_message);
 }
 
+enum cursor_type {
+       XWM_CURSOR_TOP,
+       XWM_CURSOR_BOTTOM,
+       XWM_CURSOR_LEFT,
+       XWM_CURSOR_RIGHT,
+       XWM_CURSOR_TOP_LEFT,
+       XWM_CURSOR_TOP_RIGHT,
+       XWM_CURSOR_BOTTOM_LEFT,
+       XWM_CURSOR_BOTTOM_RIGHT,
+       XWM_CURSOR_LEFT_PTR,
+};
+
+static const char *cursors[] = {
+       "top_side",
+       "bottom_side",
+       "left_side",
+       "right_side",
+       "top_left_corner",
+       "top_right_corner",
+       "bottom_left_corner",
+       "bottom_right_corner",
+       "left_ptr"
+};
+
+static void
+weston_wm_create_cursors(struct weston_wm *wm)
+{
+       int i, count = ARRAY_LENGTH(cursors);
+
+       wm->cursors = malloc(count * sizeof(xcb_cursor_t));
+       for (i = 0; i < count; i++) {
+               wm->cursors[i] =
+                       xcb_cursor_library_load_cursor(wm, cursors[i]);
+       }
+
+       wm->last_cursor = -1;
+}
+
+static void
+weston_wm_destroy_cursors(struct weston_wm *wm)
+{
+       uint8_t i;
+
+       for (i = 0; i < ARRAY_LENGTH(cursors); i++)
+               xcb_free_cursor(wm->conn, wm->cursors[i]);
+
+       free(wm->cursors);
+}
+
+static int
+get_cursor_for_location(struct theme *t, int width, int height, int x, int y)
+{
+       int location = theme_get_location(t, x, y, width, height);
+
+       switch (location) {
+               case THEME_LOCATION_RESIZING_TOP:
+                       return XWM_CURSOR_TOP;
+               case THEME_LOCATION_RESIZING_BOTTOM:
+                       return XWM_CURSOR_BOTTOM;
+               case THEME_LOCATION_RESIZING_LEFT:
+                       return XWM_CURSOR_LEFT;
+               case THEME_LOCATION_RESIZING_RIGHT:
+                       return XWM_CURSOR_RIGHT;
+               case THEME_LOCATION_RESIZING_TOP_LEFT:
+                       return XWM_CURSOR_TOP_LEFT;
+               case THEME_LOCATION_RESIZING_TOP_RIGHT:
+                       return XWM_CURSOR_TOP_RIGHT;
+               case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
+                       return XWM_CURSOR_BOTTOM_LEFT;
+               case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
+                       return XWM_CURSOR_BOTTOM_RIGHT;
+               case THEME_LOCATION_EXTERIOR:
+               case THEME_LOCATION_TITLEBAR:
+               default:
+                       return XWM_CURSOR_LEFT_PTR;
+       }
+}
+
+static void
+weston_wm_frame_set_cursor(struct weston_wm *wm,
+                          struct weston_wm_window *window, int cursor)
+{
+       uint32_t cursor_value_list;
+
+       if (!window->frame_id)
+               return;
+
+       if (wm->last_cursor == cursor)
+               return;
+
+       wm->last_cursor = cursor;
+
+       cursor_value_list = wm->cursors[cursor];
+       xcb_change_window_attributes (wm->conn, window->frame_id,
+                                     XCB_CW_CURSOR, &cursor_value_list);
+       xcb_flush(wm->conn);
+}
+
 static void
 weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
 {
@@ -971,6 +1072,55 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
        }
 }
 
+static void
+weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event)
+{
+       xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event;
+       struct weston_wm_window *window;
+       int cursor, width, height;
+
+       window = hash_table_lookup(wm->window_hash, motion->event);
+       if (!window)
+               return;
+
+       weston_wm_window_get_frame_size(window, &width, &height);
+       cursor = get_cursor_for_location(wm->theme, width, height,
+                                        motion->event_x, motion->event_y);
+
+       weston_wm_frame_set_cursor(wm, window, cursor);
+}
+
+static void
+weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event)
+{
+       xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *) event;
+       struct weston_wm_window *window;
+       int cursor, width, height;
+
+       window = hash_table_lookup(wm->window_hash, enter->event);
+       if (!window)
+               return;
+
+       weston_wm_window_get_frame_size(window, &width, &height);
+       cursor = get_cursor_for_location(wm->theme, width, height,
+                                        enter->event_x, enter->event_y);
+
+       weston_wm_frame_set_cursor(wm, window, cursor);
+}
+
+static void
+weston_wm_handle_leave(struct weston_wm *wm, xcb_generic_event_t *event)
+{
+       xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *) event;
+       struct weston_wm_window *window;
+
+       window = hash_table_lookup(wm->window_hash, leave->event);
+       if (!window)
+               return;
+
+       weston_wm_frame_set_cursor(wm, window, XWM_CURSOR_LEFT_PTR);
+}
+
 static int
 weston_wm_handle_event(int fd, uint32_t mask, void *data)
 {
@@ -990,6 +1140,15 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
                case XCB_BUTTON_RELEASE:
                        weston_wm_handle_button(wm, event);
                        break;
+               case XCB_ENTER_NOTIFY:
+                       weston_wm_handle_enter(wm, event);
+                       break;
+               case XCB_LEAVE_NOTIFY:
+                       weston_wm_handle_leave(wm, event);
+                       break;
+               case XCB_MOTION_NOTIFY:
+                       weston_wm_handle_motion(wm, event);
+                       break;
                case XCB_CREATE_NOTIFY:
                        weston_wm_handle_create_notify(wm, event);
                        break;
@@ -1284,6 +1443,8 @@ weston_wm_create(struct weston_xserver *wxs)
        wl_signal_add(&wxs->compositor->activate_signal,
                      &wm->activate_listener);
 
+       weston_wm_create_cursors(wm);
+
        weston_log("created wm\n");
 
        return wm;
@@ -1294,6 +1455,7 @@ weston_wm_destroy(struct weston_wm *wm)
 {
        /* FIXME: Free windows in hash. */
        hash_table_destroy(wm->window_hash);
+       weston_wm_destroy_cursors(wm);
        xcb_disconnect(wm->conn);
        wl_event_source_remove(wm->source);
        wl_list_remove(&wm->selection_listener.link);
index fb68671..7e1ea45 100644 (file)
@@ -58,6 +58,8 @@ struct weston_wm {
        xcb_window_t wm_window;
        struct weston_wm_window *focus_window;
        struct theme *theme;
+       xcb_cursor_t *cursors;
+       int last_cursor;
        xcb_render_pictforminfo_t format_rgb, format_rgba;
        struct wl_listener activate_listener;