rip out the VIDMODE extension stuff. this was only used to size fullscreen windows...
[mikachu/openbox.git] / openbox / client.c
index 4e31460..839bbae 100644 (file)
@@ -126,7 +126,7 @@ void client_set_list()
         windows = NULL;
 
     PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_client_list, window, (guint32*)windows, size);
+                net_client_list, window, (gulong*)windows, size);
 
     if (windows)
         g_free(windows);
@@ -204,6 +204,34 @@ void client_manage_all()
     XFree(children);
 }
 
+/* This should possibly do something more interesting than just match
+ * against WM_CLASS literally. */
+static ObAppSettings *get_settings(ObClient *client)
+{
+    GSList *a = config_per_app_settings;
+
+    while (a) {
+        ObAppSettings *app = (ObAppSettings *) a->data;
+        
+        if (
+            (app->name && !app->class && !strcmp(app->name, client->name))
+            || (app->class && !app->name && !strcmp(app->class, client->class))
+            || (app->class && app->name && !strcmp(app->class, client->class)
+                && !strcmp(app->name, client->name))
+            ) {
+            ob_debug("Window matching: %s\n", app->name);
+            /* Match if no role was specified in the per app setting, or if the string
+             * matches the beginning of the role, since apps like to set the role to
+             * things like browser-window-23c4b2f */
+            if (!app->role || !strncmp(app->role, client->role, strlen(app->role)))
+                return app;
+        }
+
+        a = a->next;
+    }
+    return NULL;
+}
+
 void client_manage(Window window)
 {
     ObClient *self;
@@ -212,6 +240,7 @@ void client_manage(Window window)
     XSetWindowAttributes attrib_set;
     XWMHints *wmhint;
     gboolean activate = FALSE;
+    ObAppSettings *settings;
 
     grab_server(TRUE);
 
@@ -292,12 +321,58 @@ void client_manage(Window window)
 
     client_apply_startup_state(self);
 
+    /* get and set application level settings */
+    settings = get_settings(self);
+
+    if (settings) {
+        /* Don't worry, we won't actually both shade and undecorate the
+         * window when push comes to shove. */
+        if (settings->shade != -1)
+            client_shade(self, settings->shade);
+        if (settings->decor != -1)
+            client_set_undecorated(self, !settings->decor);
+        if (settings->iconic != -1)
+            client_iconify(self, settings->iconic, FALSE);
+        if (settings->skip_pager != -1) {
+            self->skip_pager = !!settings->skip_pager;
+            client_change_state(self);
+        }
+        if (settings->skip_taskbar != -1) {
+            self->skip_taskbar = !!settings->skip_taskbar;
+            client_change_state(self);
+        }
+
+        /* 1 && -1 shouldn't be possible by the code in config.c */
+        if (settings->max_vert == 1 && self->max_horz == 1)
+            client_maximize(self, TRUE, 0, TRUE);
+        else if (settings->max_vert == 0 && self->max_horz == 0)
+            client_maximize(self, FALSE, 0, TRUE);
+        else if (settings->max_vert == 1 && self->max_horz == 0) {
+            client_maximize(self, TRUE, 2, TRUE);
+            client_maximize(self, FALSE, 1, TRUE);
+        } else if (settings->max_vert == 0 && self->max_horz == 1) {
+            client_maximize(self, TRUE, 1, TRUE);
+            client_maximize(self, FALSE, 2, TRUE);
+        }
+
+        if (settings->fullscreen != -1)
+            client_fullscreen(self, !!settings->fullscreen, TRUE);
+
+        if (settings->desktop < screen_num_desktops)
+            client_set_desktop(self, settings->desktop, FALSE);
+
+        if (settings->layer > -2 && settings->layer < 2)
+            client_set_layer(self, settings->layer);
+
+    }
+
     stacking_add(CLIENT_AS_WINDOW(self));
     client_restore_session_stacking(self);
 
     /* focus the new window? */
     if (ob_state() != OB_STATE_STARTING &&
-        (config_focus_new || client_search_focus_parent(self)) &&
+        (config_focus_new || client_search_focus_parent(self)) ||
+        (settings && settings->focus == TRUE) &&
         /* note the check against Type_Normal/Dialog, not client_normal(self),
            which would also include other types. in this case we want more
            strict rules for focus */
@@ -342,19 +417,27 @@ void client_manage(Window window)
         gint x = self->area.x, ox = x;
         gint y = self->area.y, oy = y;
 
-        place_client(self, &x, &y);
+        place_client(self, &x, &y, settings);
 
-        /* make sure the window is visible */
+        /* make sure the window is visible. */
         client_find_onscreen(self, &x, &y,
                              self->frame->area.width,
                              self->frame->area.height,
                              /* non-normal clients has less rules, and
-                                windows that are being restored from a session
-                                do also. we can assume you want it back where
-                                you saved it */
-                             client_normal(self) && !self->session);
-
-        if (x != ox || y != oy)
+                                windows that are being restored from a
+                                session do also. we can assume you want
+                                it back where you saved it. Clients saying
+                                they placed themselves are subjected to
+                                harder rules, ones that are placed by
+                                place.c or by the user are allowed partially
+                                off-screen and on xinerama divides (ie,
+                                it is up to the placement routines to avoid
+                                the xinerama divides) */
+                             ((self->positioned & PPosition) &&
+                              !(self->positioned & USPosition)) &&
+                             client_normal(self) &&
+                             !self->session);
+        if (x != ox || y != oy)         
             client_move(self, x, y);
     }
 
@@ -544,7 +627,7 @@ static void client_restore_session_state(ObClient *self)
     self->session = it->data;
 
     RECT_SET_POINT(self->area, self->session->x, self->session->y);
-    self->positioned = TRUE;
+    self->positioned = PPosition;
     if (self->session->w > 0)
         self->area.width = self->session->w;
     if (self->session->h > 0)
@@ -611,9 +694,10 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
                                                 would be */
 
     /* XXX watch for xinerama dead areas */
-
-    a = screen_area(self->desktop);
+    /* This makes sure windows aren't entirely outside of the screen so you
+     * can't see them at all */
     if (client_normal(self)) {
+        a = screen_area(self->desktop);
         if (!self->strut.right && *x >= a->x + a->width - 1)
             *x = a->x + a->width - self->frame->area.width;
         if (!self->strut.bottom && *y >= a->y + a->height - 1)
@@ -624,10 +708,17 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
             *y = a->y;
     }
 
+    /* This here doesn't let windows even a pixel outside the screen,
+     * when called from client_manage, programs placing themselves are
+     * forced completely onscreen, while things like
+     * xterm -geometry resolution-width/2 will work fine. Trying to
+     * place it completely offscreen will be handled in the above code.
+     * Sorry for this confused comment, i am tired. */
     if (rude) {
-        /* this is my MOZILLA BITCHSLAP. oh ya it fucking feels good.
-           Java can suck it too. */
-
+        /* avoid the xinerama monitor divide while we're at it,
+         * remember to fix the placement stuff to avoid it also and
+         * then remove this XXX */
+        a = screen_physical_area_monitor(client_monitor(self));
         /* dont let windows map/move into the strut unless they
            are bigger than the available area */
         if (w <= a->width) {
@@ -1111,7 +1202,7 @@ void client_update_normal_hints(ObClient *self)
         /* normal windows can't request placement! har har
         if (!client_normal(self))
         */
-        self->positioned = !!(size.flags & (PPosition|USPosition));
+        self->positioned = (size.flags & (PPosition|USPosition));
 
         if (size.flags & PWinGravity) {
             self->gravity = size.win_gravity;
@@ -1212,7 +1303,7 @@ void client_setup_decor_and_functions(ObClient *self)
                    (self->mwmhints.decorations & OB_MWM_DECOR_TITLE)))
                 /* if the mwm hints request no handle or title, then all
                    decorations are disabled */
-                self->decorations = 0;
+                self->decorations = config_theme_keepborder ? OB_FRAME_DECOR_BORDER : 0;
         }
     }
 
@@ -1284,7 +1375,7 @@ void client_setup_decor_and_functions(ObClient *self)
 
 static void client_change_allowed_actions(ObClient *self)
 {
-    guint32 actions[9];
+    gulong actions[9];
     gint num = 0;
 
     /* desktop windows are kept on all desktops */
@@ -1699,8 +1790,8 @@ void client_update_icons(ObClient *self)
 
 static void client_change_state(ObClient *self)
 {
-    guint32 state[2];
-    guint32 netstate[11];
+    gulong state[2];
+    gulong netstate[11];
     guint num;
 
     state[0] = self->wmstate;
@@ -1788,9 +1879,8 @@ static ObStackingLayer calc_layer(ObClient *self)
     else if (self->type == OB_CLIENT_TYPE_DESKTOP)
         l = OB_STACKING_LAYER_DESKTOP;
     else if (self->type == OB_CLIENT_TYPE_DOCK) {
-        if (self->above) l = OB_STACKING_LAYER_DOCK_ABOVE;
-        else if (self->below) l = OB_STACKING_LAYER_DOCK_BELOW;
-        else l = OB_STACKING_LAYER_DOCK_NORMAL;
+        if (self->below) l = OB_STACKING_LAYER_NORMAL;
+        else l = OB_STACKING_LAYER_ABOVE;
     }
     else if (self->above) l = OB_STACKING_LAYER_ABOVE;
     else if (self->below) l = OB_STACKING_LAYER_BELOW;
@@ -1945,35 +2035,16 @@ void client_configure_full(ObClient *self, ObCorner anchor,
 
     /* set the size and position if fullscreen */
     if (self->fullscreen) {
-#ifdef VIDMODE
-        gint dot;
-        XF86VidModeModeLine mode;
-#endif
         Rect *a;
         guint i;
 
         i = client_monitor(self);
         a = screen_physical_area_monitor(i);
 
-#ifdef VIDMODE
-        if (i == 0 && /* primary head */
-            extensions_vidmode &&
-            XF86VidModeGetViewPort(ob_display, ob_screen, &x, &y) &&
-            /* get the mode last so the mode.privsize isnt freed incorrectly */
-            XF86VidModeGetModeLine(ob_display, ob_screen, &dot, &mode)) {
-            x += a->x;
-            y += a->y;
-            w = mode.hdisplay;
-            h = mode.vdisplay;
-            if (mode.privsize) XFree(mode.private);
-        } else
-#endif
-        {
-            x = a->x;
-            y = a->y;
-            w = a->width;
-            h = a->height;
-        }
+        x = a->x;
+        y = a->y;
+        w = a->width;
+        h = a->height;
 
         user = FALSE; /* ignore that increment etc shit when in fullscreen */
     } else {
@@ -2257,12 +2328,6 @@ static void client_iconify_recursive(ObClient *self,
             focus_order_remove(self);
             focus_order_add_new(self);
 
-            /* this is here cuz with the VIDMODE extension, the viewport can
-               change while a fullscreen window is iconic, and when it
-               uniconifies, it would be nice if it did so to the new position
-               of the viewport */
-            client_reconfigure(self);
-
             changed = TRUE;
         }
     }
@@ -2782,6 +2847,9 @@ void client_unfocus(ObClient *self)
 
 void client_activate(ObClient *self, gboolean here)
 {
+    /* This check is for the client_list_menu trying to activate
+     * a closed client. */
+    if (!g_list_find(client_list, self)) return;
     if (client_normal(self) && screen_showing_desktop)
         screen_show_desktop(FALSE);
     if (self->iconic)
@@ -3002,10 +3070,20 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
     if (self->undecorated != undecorated) {
         self->undecorated = undecorated;
         client_setup_decor_and_functions(self);
+        /* Make sure the client knows it might have moved. Maybe there is a
+         * better way of doing this so only one client_configure is sent, but
+         * since 125 of these are sent per second when moving the window (with
+         * user = FALSE) i doubt it matters much.
+         */
+        client_configure(self, OB_CORNER_TOPLEFT, self->area.x, self->area.y,
+                         self->area.width, self->area.height, TRUE, TRUE);
         client_change_state(self); /* reflect this in the state hints */
     }
 }
 
+/* Determines which physical monitor a client is on by calculating the
+   area of the part of the client on each monitor.  The number of the
+   monitor containing the greatest area of the client is returned.*/
 guint client_monitor(ObClient *self)
 {
     guint i;
@@ -3132,15 +3210,16 @@ void client_update_sm_client_id(ObClient *self)
  */
 gint client_directional_edge_search(ObClient *c, ObDirection dir)
 {
-    gint dest;
+    gint dest, monitor_dest;
     gint my_edge_start, my_edge_end, my_offset;
     GList *it;
-    Rect *a;
+    Rect *a, *monitor;
     
     if(!client_list)
         return -1;
 
     a = screen_area(c->desktop);
+    monitor = screen_area_monitor(c->desktop, client_monitor(c));
 
     switch(dir) {
     case OB_DIRECTION_NORTH:
@@ -3150,8 +3229,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         
         /* default: top of screen */
         dest = a->y;
+        monitor_dest = monitor->y;
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset > monitor_dest)
+            dest = monitor_dest; 
 
-        for(it = client_list; it; it = g_list_next(it)) {
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3193,8 +3277,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
 
         /* default: bottom of screen */
         dest = a->y + a->height;
+        monitor_dest = monitor->y + monitor->height;
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset < monitor_dest)
+            dest = monitor_dest; 
 
-        for(it = client_list; it; it = g_list_next(it)) {
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3237,8 +3326,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
 
         /* default: leftmost egde of screen */
         dest = a->x;
+        monitor_dest = monitor->x;
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset > monitor_dest)
+            dest = monitor_dest;            
 
-        for(it = client_list; it; it = g_list_next(it)) {
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;
 
@@ -3281,8 +3375,13 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir)
         
         /* default: rightmost edge of screen */
         dest = a->x + a->width;
+        monitor_dest = monitor->x + monitor->width;
+        /* if the monitor edge comes before the screen edge, */
+        /* use that as the destination instead. (For xinerama) */
+        if (monitor_dest != dest && my_offset < monitor_dest)
+            dest = monitor_dest;            
 
-        for(it = client_list; it; it = g_list_next(it)) {
+        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
             gint his_edge_start, his_edge_end, his_offset;
             ObClient *cur = it->data;