screen.c 10.6 KB
Newer Older
rhp's avatar
...  
rhp committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Metacity X screen handler */

/* 
 * 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.
 */
rhp's avatar
...    
rhp committed
21

rhp's avatar
...  
rhp committed
22
23
#include "screen.h"
#include "util.h"
rhp's avatar
...    
rhp committed
24
#include "errors.h"
rhp's avatar
...    
rhp committed
25
#include "window.h"
rhp's avatar
...    
rhp committed
26
#include "frame.h"
rhp's avatar
...    
rhp committed
27
28
#include "workspace.h"
#include "keybindings.h"
rhp's avatar
...    
rhp committed
29
#include "stack.h"
rhp's avatar
...    
rhp committed
30

rhp's avatar
...    
rhp committed
31
#include <X11/Xatom.h>
rhp's avatar
...    
rhp committed
32
33
#include <locale.h>
#include <string.h>
rhp's avatar
...  
rhp committed
34

rhp's avatar
...    
rhp committed
35
36
37
38
static char* get_screen_name (MetaDisplay *display,
                              int          number);


rhp's avatar
...    
rhp committed
39
40
41
42
43
static int
set_wm_check_hint (MetaScreen *screen)
{
  unsigned long data[1];

rhp's avatar
...    
rhp committed
44
45
  g_return_val_if_fail (screen->display->leader_window != None, 0);
  
rhp's avatar
...    
rhp committed
46
47
48
49
50
51
  data[0] = screen->display->leader_window;

  XChangeProperty (screen->display->xdisplay, screen->xroot,
                   screen->display->atom_net_supporting_wm_check,
                   XA_WINDOW,
                   32, PropModeReplace, (guchar*) data, 1);
rhp's avatar
...    
rhp committed
52
53
54
55

  /* Legacy GNOME hint */
  XChangeProperty (screen->display->xdisplay, screen->xroot,
                   screen->display->atom_win_supporting_wm_check,
rhp's avatar
...    
rhp committed
56
                   XA_CARDINAL,
rhp's avatar
...    
rhp committed
57
58
                   32, PropModeReplace, (guchar*) data, 1);

rhp's avatar
...    
rhp committed
59
60
61
62
63
64
  return Success;
}

static int
set_supported_hint (MetaScreen *screen)
{
rhp's avatar
...    
rhp committed
65
#define N_SUPPORTED 21
rhp's avatar
...    
rhp committed
66
#define N_WIN_SUPPORTED 1
rhp's avatar
...    
rhp committed
67
  Atom atoms[N_SUPPORTED];
rhp's avatar
...    
rhp committed
68
  
rhp's avatar
...    
rhp committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  atoms[0] = screen->display->atom_net_wm_name;
  atoms[1] = screen->display->atom_net_close_window;
  atoms[2] = screen->display->atom_net_wm_state;
  atoms[3] = screen->display->atom_net_wm_state_shaded;
  atoms[4] = screen->display->atom_net_wm_state_maximized_vert;
  atoms[5] = screen->display->atom_net_wm_state_maximized_horz;
  atoms[6] = screen->display->atom_net_wm_desktop;
  atoms[7] = screen->display->atom_net_number_of_desktops;
  atoms[8] = screen->display->atom_net_current_desktop;
  atoms[9] = screen->display->atom_net_wm_window_type;
  atoms[10] = screen->display->atom_net_wm_window_type_desktop;
  atoms[11] = screen->display->atom_net_wm_window_type_dock;
  atoms[12] = screen->display->atom_net_wm_window_type_toolbar;
  atoms[13] = screen->display->atom_net_wm_window_type_menu;
  atoms[14] = screen->display->atom_net_wm_window_type_dialog;
  atoms[15] = screen->display->atom_net_wm_window_type_normal;
  atoms[16] = screen->display->atom_net_wm_state_modal;
rhp's avatar
...    
rhp committed
86
87
  atoms[17] = screen->display->atom_net_client_list;
  atoms[18] = screen->display->atom_net_client_list_stacking;
rhp's avatar
...    
rhp committed
88
89
  atoms[19] = screen->display->atom_net_wm_state_skip_taskbar;
  atoms[20] = screen->display->atom_net_wm_state_skip_pager;
rhp's avatar
...    
rhp committed
90
91
92
93
94
95
  
  XChangeProperty (screen->display->xdisplay, screen->xroot,
                   screen->display->atom_net_wm_supported,
                   XA_ATOM,
                   32, PropModeReplace, (guchar*) atoms, N_SUPPORTED);

rhp's avatar
...    
rhp committed
96
97
98
99
100
101
102
103
  /* Set legacy GNOME hints */
  atoms[0] = screen->display->atom_win_layer;
  
  XChangeProperty (screen->display->xdisplay, screen->xroot,
                   screen->display->atom_win_protocols,
                   XA_ATOM,
                   32, PropModeReplace, (guchar*) atoms, N_WIN_SUPPORTED);
  
rhp's avatar
...    
rhp committed
104
105
106
107
  return Success;
#undef N_SUPPORTED
}

rhp's avatar
...  
rhp committed
108
109
110
111
112
MetaScreen*
meta_screen_new (MetaDisplay *display,
                 int          number)
{
  MetaScreen *screen;
rhp's avatar
...    
rhp committed
113
114
  Window xroot;
  Display *xdisplay;
rhp's avatar
...    
rhp committed
115
  
rhp's avatar
...    
rhp committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  /* Only display->name, display->xdisplay, and display->error_traps
   * can really be used in this function, since normally screens are
   * created from the MetaDisplay constructor
   */
  
  xdisplay = display->xdisplay;
  
  meta_verbose ("Trying screen %d on display '%s'\n",
                number, display->name);

  xroot = RootWindow (xdisplay, number);

  /* FVWM checks for None here, I don't know if this
   * ever actually happens
   */
  if (xroot == None)
    {
      meta_warning (_("Screen %d on display '%s' is invalid\n"),
                    number, display->name);
      return NULL;
    }

  /* Select our root window events */
  meta_error_trap_push (display);
  XSelectInput (xdisplay,
                xroot,
                SubstructureRedirectMask | SubstructureNotifyMask |
                ColormapChangeMask | PropertyChangeMask |
                LeaveWindowMask | EnterWindowMask |
                ButtonPressMask | ButtonReleaseMask);
  if (meta_error_trap_pop (display) != Success)
    {
      meta_warning (_("Screen %d on display '%s' already has a window manager\n"),
                    number, display->name);
      return NULL;
    }
rhp's avatar
...  
rhp committed
152
153
154
  
  screen = g_new (MetaScreen, 1);

rhp's avatar
...    
rhp committed
155
  screen->display = display;
rhp's avatar
...  
rhp committed
156
  screen->number = number;
rhp's avatar
...    
rhp committed
157
  screen->screen_name = get_screen_name (display, number);
rhp's avatar
...    
rhp committed
158
  screen->xscreen = ScreenOfDisplay (xdisplay, number);
rhp's avatar
...    
rhp committed
159
  screen->xroot = xroot;
rhp's avatar
...    
rhp committed
160
161
  screen->width = WidthOfScreen (screen->xscreen);
  screen->height = HeightOfScreen (screen->xscreen);
rhp's avatar
...    
rhp committed
162
163
164
  screen->current_cursor = -1; /* invalid/unset */
  
  meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
rhp's avatar
...    
rhp committed
165
  
rhp's avatar
...    
rhp committed
166
167
168
169
170
  if (display->leader_window == None)
    display->leader_window = XCreateSimpleWindow (display->xdisplay,
                                                  screen->xroot,
                                                  -100, -100, 1, 1, 0, 0, 0);
  
rhp's avatar
...    
rhp committed
171
172
173
174
  set_supported_hint (screen);
  
  set_wm_check_hint (screen);
  
rhp's avatar
...    
rhp committed
175
176
177
178
  /* Screens must have at least one workspace at all times,
   * so create that required workspace.
   */
  screen->active_workspace = meta_workspace_new (screen);
rhp's avatar
...    
rhp committed
179
180
181
182
183
  /* FIXME, for now there are always 6 workspaces... */
  meta_workspace_new (screen);
  meta_workspace_new (screen);
  meta_workspace_new (screen);
  meta_workspace_new (screen);
rhp's avatar
...    
rhp committed
184
  meta_workspace_new (screen);
rhp's avatar
...    
rhp committed
185

rhp's avatar
...    
rhp committed
186
  meta_screen_grab_keys (screen);
rhp's avatar
...    
rhp committed
187

rhp's avatar
...    
rhp committed
188
  screen->ui = meta_ui_new (screen->display->xdisplay,
rhp's avatar
...    
rhp committed
189
                            screen->xscreen);
rhp's avatar
...    
rhp committed
190
191

  screen->stack = meta_stack_new (screen);
rhp's avatar
...    
rhp committed
192
  
rhp's avatar
...    
rhp committed
193
194
  meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
                screen->number, screen->screen_name, screen->xroot);  
rhp's avatar
...  
rhp committed
195
196
197
198
199
200
  
  return screen;
}

void
meta_screen_free (MetaScreen *screen)
rhp's avatar
...    
rhp committed
201
{  
rhp's avatar
...    
rhp committed
202
203
  meta_screen_ungrab_keys (screen);
  
rhp's avatar
...    
rhp committed
204
  meta_ui_free (screen->ui);
rhp's avatar
...    
rhp committed
205

rhp's avatar
...    
rhp committed
206
207
  meta_stack_free (screen->stack);
  
rhp's avatar
...    
rhp committed
208
  g_free (screen->screen_name);
rhp's avatar
...  
rhp committed
209
210
211
  g_free (screen);
}

rhp's avatar
...    
rhp committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
void
meta_screen_manage_all_windows (MetaScreen *screen)
{
  Window ignored1, ignored2;
  Window *children;
  unsigned int n_children;
  int i;

  /* Must grab server to avoid obvious race condition */
  meta_display_grab (screen->display);

  meta_error_trap_push (screen->display);
  
  XQueryTree (screen->display->xdisplay,
              screen->xroot,
              &ignored1, &ignored2, &children, &n_children);
rhp's avatar
...  
rhp committed
228

rhp's avatar
...    
rhp committed
229
230
231
232
233
  if (meta_error_trap_pop (screen->display))
    {
      meta_display_ungrab (screen->display);
      return;
    }
rhp's avatar
...    
rhp committed
234
235

  meta_stack_freeze (screen->stack);
rhp's avatar
...    
rhp committed
236
237
238
  i = 0;
  while (i < n_children)
    {
rhp's avatar
...    
rhp committed
239
      meta_window_new (screen->display, children[i], TRUE);
rhp's avatar
...    
rhp committed
240
241
242

      ++i;
    }
rhp's avatar
...    
rhp committed
243
  meta_stack_thaw (screen->stack);
rhp's avatar
...    
rhp committed
244
245
246
247
248
249

  meta_display_ungrab (screen->display);
  
  if (children)
    XFree (children);
}
rhp's avatar
...    
rhp committed
250
251
252
253
254
255
256
257
258
259
260
261
262

MetaScreen*
meta_screen_for_x_screen (Screen *xscreen)
{
  MetaDisplay *display;
  
  display = meta_display_for_x_display (DisplayOfScreen (xscreen));

  if (display == NULL)
    return NULL;
  
  return meta_display_screen_for_x_screen (display, xscreen);
}
rhp's avatar
...    
rhp committed
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

static char*
get_screen_name (MetaDisplay *display,
                 int          number)
{
  char *p;
  char *dname;
  char *scr;
  
  /* DisplayString gives us a sort of canonical display,
   * vs. the user-entered name from XDisplayName()
   */
  dname = g_strdup (DisplayString (display->xdisplay));

  /* Change display name to specify this screen.
   */
  p = strrchr (dname, ':');
  if (p)
    {
      p = strchr (p, '.');
      if (p)
        *p = '\0';
    }
  
  scr = g_strdup_printf ("%s.%d", dname, number);

  g_free (dname);

  return scr;
}
rhp's avatar
...    
rhp committed
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365

static gint
ptrcmp (gconstpointer a, gconstpointer b)
{
  if (a < b)
    return -1;
  else if (a > b)
    return 1;
  else
    return 0;
}

static void
listify_func (gpointer key, gpointer value, gpointer data)
{
  GSList **listp;
  
  listp = data;

  *listp = g_slist_prepend (*listp, value);
}

void
meta_screen_foreach_window (MetaScreen *screen,
                            MetaScreenWindowFunc func,
                            gpointer data)
{
  GSList *winlist;
  GSList *tmp;

  /* If we end up doing this often, just keeping a list
   * of windows might be sensible.
   */
  
  winlist = NULL;
  g_hash_table_foreach (screen->display->window_ids,
                        listify_func,
                        &winlist);
  
  winlist = g_slist_sort (winlist, ptrcmp);
  
  tmp = winlist;
  while (tmp != NULL)
    {
      /* If the next node doesn't contain this window
       * a second time, delete the window.
       */
      if (tmp->next == NULL ||
          (tmp->next && tmp->next->data != tmp->data))
        {
          MetaWindow *window = tmp->data;

          if (window->screen == screen)
            (* func) (screen, window, data);
        }
      
      tmp = tmp->data;
    }
  g_slist_free (winlist);
}

static void
queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
{
  if (window->frame)
    meta_frame_queue_draw (window->frame);
}

void
meta_screen_queue_frame_redraws (MetaScreen *screen)
{
  meta_screen_foreach_window (screen, queue_draw, NULL);
}
rhp's avatar
...    
rhp committed
366

rhp's avatar
...    
rhp committed
367
368
369
370
371
372
373
374
375
376
377
static void
queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
{
  meta_window_queue_move_resize (window);
}

void
meta_screen_queue_window_resizes (MetaScreen *screen)
{
  meta_screen_foreach_window (screen, queue_resize, NULL);
}
rhp's avatar
...    
rhp committed
378

rhp's avatar
rhp committed
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
int
meta_screen_get_n_workspaces (MetaScreen *screen)
{
  GList *tmp;
  int i;

  i = 0;
  tmp = screen->display->workspaces;
  while (tmp != NULL)
    {
      MetaWorkspace *w = tmp->data;

      if (w->screen == screen)
        ++i;
      
      tmp = tmp->next;
    }

  return i;

}
rhp's avatar
...    
rhp committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

void
meta_screen_set_cursor (MetaScreen *screen,
                        MetaCursor  cursor)
{
  Cursor xcursor;

  if (cursor == screen->current_cursor)
    return;

  screen->current_cursor = cursor;
  
  xcursor = meta_display_create_x_cursor (screen->display, cursor);
  XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
  XFreeCursor (screen->display->xdisplay, xcursor);
}