void stack(node_t *n, bool focused) { if (IS_FLOATING(n->client) && !auto_raise) { return; } if (stack_head == NULL) { stack_insert_after(NULL, n); } else { stacking_list_t *s = (focused ? limit_above(n) : limit_below(n)); if (s == NULL) { return; } int i = stack_cmp(n->client, s->node->client); if (i < 0 || (i == 0 && !focused)) { stack_insert_before(s, n); window_below(n->client->window, s->node->client->window); } else { stack_insert_after(s, n); window_above(n->client->window, s->node->client->window); } } }
/* * XXX warn about ``unsigned char *'' vs ``char *'', * unlike gcc */ static int compare_tlist(struct type_node *dest, struct type_node *src, int flag) { struct type_node *dest_start = dest; for (; dest != NULL && src != NULL; dest = dest->next, src = src->next) { if (src->type == TN_FUNCTION || dest->type == TN_FUNCTION) { if (dest->type != src->type) { /* XXX fix this later */ if (dest == dest_start) { /* * Ordinary function symbols are * compatible with pointers to * functions */ if (dest->type == TN_FUNCTION) { if (src->type == TN_POINTER_TO) { src = src->next; } else { return -1; } } else { if (dest->type == TN_POINTER_TO) { dest = dest->next; } else { return -1; } } } } } if (dest->type != src->type) { /* Pointer vs array vs function */ if (flag & CMPTY_ARRAYPTR) { if ((dest->type == TN_ARRAY_OF || src->type == TN_ARRAY_OF || dest->type == TN_VARARRAY_OF || src->type == TN_VARARRAY_OF) && (dest->type == TN_POINTER_TO || src->type == TN_POINTER_TO)) { continue; } } return -1; } switch (dest->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: if (flag & CMPTY_TENTDEC) { #if REMOVE_ARRARG if (!dest->have_array_size || !src->have_array_size) { #else if (dest->arrarg->const_value == NULL || src->arrarg->const_value == NULL) { #endif /* * probably * extern int foo[]; * int foo[123]; * -> OK! */ break; } } if (dest->arrarg_const != src->arrarg_const && ((flag & CMPTY_ARRAYPTR) == 0 || dest_start != dest)) { #if REMOVE_ARRARG if (!src->have_array_size || !dest->have_array_size) { #else if (src->arrarg->const_value == NULL || dest->arrarg->const_value == NULL) { #endif /* * One side has unspecified size, this * is OK! * extern char foo[]; * char (*p)[5] = &foo; * char bar[5]; * char (*p2)[] = &bar; */ break; } else { /* Array sizes differ */ return -1; } } break; case TN_POINTER_TO: break; case TN_FUNCTION: if (compare_tfunc(dest->tfunc, src->tfunc) == -1) { return -1; } break; } } if (dest != NULL || src != NULL) { /* One list is longer, so it differs by definition */ return -1; } return 0; } #endif /* #ifndef PREPROCESSOR */ int compare_types(struct type *dest, struct type *src, int flag) { int is_void_ptr = 0; /* 04/08/08: Changed this (for the better, hopefully!) */ if (dest->tlist != NULL && dest->tlist->type == TN_POINTER_TO && dest->tlist->next == NULL && dest->code == TY_VOID) { is_void_ptr = 1; } else if (src->tlist != NULL && src->tlist->type == TN_POINTER_TO && src->tlist->next == NULL && src->code == TY_VOID) { is_void_ptr = 1; } if (dest->code != src->code) { /* * Differing base type - This is ok if we have a void * pointer vs a non-void pointer, otherwise return error */ if (!is_void_ptr || src->tlist == NULL || dest->tlist == NULL) { return -1; } } if (flag & CMPTY_SIGN) { if (dest->sign != dest->sign) { /* Differing sign */ return -1; } } if (flag & CMPTY_CONST) { if (IS_CONST(dest->flags) != IS_CONST(src->flags)) { /* One is const-qualified */ /*return -1;*/ } } /* * 04/08/08: Skip the tlist comparison if this is void pointer * vs non-void pointer; Otherwise tlists of different length * will compare uneven, as in void * vs int **, which is wrong */ if (is_void_ptr) { return 0; } #ifndef PREPROCESSOR return compare_tlist(dest->tlist, src->tlist, flag); #else return -1; #endif } int check_init_type(struct type *ofwhat, struct expr *init) { if (ofwhat->tlist == NULL) { if (init->next != NULL) { } } else if (ofwhat->tlist->type == TN_ARRAY_OF) { if (init->type->code == TOK_STRING_LITERAL) { return 0; } else { struct expr *ex; for (ex = init; ex != NULL; ex = ex->next) { } } } return 0; } void copy_type(struct type *dest, const struct type *src, int fullcopy) { if (fullcopy) { memcpy(dest, src, sizeof *dest); } else { memcpy(dest, src, sizeof *dest); } } struct type_node * copy_tlist(struct type_node **dest, const struct type_node *src) { struct type_node *head; struct type_node *tail; struct type_node *tn; if (src == NULL) { *dest = NULL; return NULL; } head = tail = NULL; do { tn = n_xmalloc(sizeof *tn); memcpy(tn, src, sizeof *tn); if (head == NULL) { head = tail = tn; } else { tail->next = tn; tail = tail->next; } } while ((src = src->next) != NULL); *dest = head; return tail; } void set_type_sign(struct type *ty) { if (ty->code == TY_UCHAR || ty->code == TY_USHORT || ty->code == TY_UINT || ty->code == TY_ULONG || ty->code == TY_ULLONG) { ty->sign = TOK_KEY_UNSIGNED; } else if (!IS_FLOATING(ty->code) && ty->code != TY_STRUCT && ty->code != TY_UNION) { ty->sign = TOK_KEY_SIGNED; } } struct type * make_basic_type(int code) { #define N_TYPES (TY_MAX - TY_MIN) #if 0 static struct type basic_types[N_TYPES]; #endif static int inited; static struct type *basic_types; if (!inited) { int i; int nbytes = N_TYPES * sizeof(struct type); int need_mprotect = 1; basic_types = debug_malloc_pages(nbytes); if (basic_types == NULL) { /* * Probably debug_malloc_pages() doesn't work * on this system */ basic_types = n_xmalloc(nbytes); need_mprotect = 0; } memset(basic_types, 0, nbytes); for (i = 0; i < N_TYPES; ++i) { basic_types[i].code = i + TY_MIN; set_type_sign(&basic_types[i]); } inited = 1; if (need_mprotect) { /* * We make the array unwritable because it really * should not be written to; Modifying it is a bug * that has happend more than once. * * The void cast is necessary because of a broken * Solaris prototype that takes caddr_t :-/ */ mprotect((void *)basic_types, nbytes, PROT_READ); } } if (code < 0 || (code - TY_MIN) >= N_TYPES) { printf("BUG: bad code for make_basic_type: %d\n", code); abort(); } #if 0 if (code == TY_PSEUDEO_SIZE_T) { static struct type ty; static struct type *p; if (p == NULL) { ty = basic_types[TY_UINT]; } } #endif #if 0 /* As of Jan 6 2007, the basic types may not be modified anymore */ basic_types[code - TY_MIN].tlist = NULL; #endif return &basic_types[code - TY_MIN]; } struct type * make_void_ptr_type(void) { static struct type *ty; if (ty == NULL) { ty = make_basic_type(TY_VOID); ty = n_xmemdup(ty, sizeof *ty); append_typelist(ty, TN_POINTER_TO, NULL, NULL, NULL); } return ty; } struct type * make_array_type(int size, int is_wide_char) { struct type *ret = alloc_type(); if (is_wide_char) { ret->code = backend->get_wchar_t()->code; ret->sign = backend->get_wchar_t()->sign; } else { ret->code = TY_CHAR; if (CHAR_MAX == UCHAR_MAX) { /* XXX */ ret->sign = TOK_KEY_UNSIGNED; } else { ret->sign = TOK_KEY_SIGNED; } } ret->storage = TOK_KEY_STATIC; ret->tlist = alloc_type_node(); ret->tlist->type = TN_ARRAY_OF; ret->tlist->arrarg_const = size; #if REMOVE_ARRARG ret->tlist->have_array_size = 1; #endif return ret; } /* * Helper function for parse_declarator()- stores pointer/array-of/function * property (specified by ``type'' argument) with optional arguments type_arg * (for pointer/array-of) and tf (for function) in type specified by t * * 01/26/08: Extended to do some sanity checking (functions may not return * functions or arrays). This means some type constructions are now REQUIRED * to go through append_typelist()! May not be the best approach, needs * testing?! */ void append_typelist(struct type *t, int type, void *type_arg, struct ty_func *tf, struct token *tok) { struct type_node *te; struct expr *ex; (void) tok; /* XXX unneeded?!?! */ /* Allocate and insert new type node */ if (t->tlist == NULL) { te = t->tlist = t->tlist_tail = alloc_type_node(); te->prev = NULL; if (type == TN_FUNCTION) { /* * If the first node in the type list is a function * designator, this means we are dealing with a genuine * function declaration/definition (as opposed to a * pointer) */ t->is_func = 1; } } else { /* * 01/26/08: Some sanity checking! */ int tailtype = t->tlist_tail->type; if (tailtype == TN_ARRAY_OF || tailtype == TN_VARARRAY_OF) { if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `array of " "functions' - Maybe you meant `array " "of pointer to function'; `void (*ar[N])();'?"); return /* -1 XXX */ ; } } else if (tailtype == TN_FUNCTION) { if (type == TN_ARRAY_OF || type == TN_VARARRAY_OF) { errorfl(tok, "Invalid declaration of `function " "returning array' - If you really want " "to return an array by value, put it " "into a structure!"); return /* -1 XXX */ ; } else if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `function " "returning function' - You can at most " "return a pointer to a function; " "`void (*foo())();'"); return /* -1 XXX */ ; } } te = alloc_type_node(); te->prev = t->tlist_tail; t->tlist_tail->next = te; t->tlist_tail = t->tlist_tail->next; } te->next = NULL; te->type = type; switch (type) { case TN_VARARRAY_OF: case TN_ARRAY_OF: #if REMOVE_ARRARG ex = type_arg; if (ex->const_value == NULL) { /* Size not specified - extern char buf[]; */ te->have_array_size = 0; } else { te->have_array_size = 1; ex->const_value->type = n_xmemdup(ex->const_value->type, sizeof(struct type)); cross_convert_tyval(ex->const_value, NULL, NULL); te->arrarg_const = cross_to_host_size_t( ex->const_value); if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->have_array_size = 0; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } if (type == TN_VARARRAY_OF) { te->variable_arrarg = ex; } #else /* Using arrarg */ te->arrarg = type_arg; if (te->arrarg->const_value) { te->arrarg->const_value->type = n_xmemdup(te->arrarg->const_value->type, sizeof(struct type)); cross_convert_tyval(te->arrarg->const_value, NULL, NULL); te->arrarg_const = /* *(size_t *) */ cross_to_host_size_t( te->arrarg->const_value); /*->value; */ if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->arrarg->const_value = NULL; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } #endif /* REMOVE_ARRARG is disabled */ break; case TN_POINTER_TO: te->ptrarg = type_arg? *(int *)type_arg: 0; break; case TN_FUNCTION: te->tfunc = tf; break; } } static struct { char *name; int code; } basic_type_names[] = { { "char", TY_CHAR }, { "unsigned char", TY_UCHAR }, { "signed char", TY_SCHAR }, { "short", TY_SHORT }, { "unsigned short", TY_USHORT }, { "int", TY_INT }, { "unsigned int", TY_UINT }, { "long", TY_LONG }, { "unsigned long", TY_ULONG }, { "float", TY_FLOAT }, { "double", TY_DOUBLE }, { "long double", TY_LDOUBLE }, { "struct", TY_STRUCT }, { "union", TY_UNION }, { "enum", TY_ENUM }, { "void", TY_VOID }, { "long long", TY_LLONG }, { "unsigned long long", TY_ULLONG }, { "_Bool", TY_BOOL }, { NULL, 0 } }; char * ret_type_to_text(struct type *ty) { struct type_node *orig_tlist = NULL; char *ret; if (ty->tlist != NULL) { orig_tlist = ty->tlist; if (ty->tlist->type == TN_FUNCTION) { ty->tlist = ty->tlist->next; } else if (ty->tlist->type == TN_POINTER_TO && ty->tlist->next != NULL && ty->tlist->next->type == TN_FUNCTION) { ty->tlist = ty->tlist->next->next; } ret = type_to_text(ty); ty->tlist = orig_tlist; } else { ret = type_to_text(ty); } return ret; } char * type_to_text(struct type *dt) { struct type_node *t; char *buf = NULL; char *p = NULL; size_t size = 0; size_t used = 0; int i; for (t = dt->tlist; t != NULL; t = t->next) { switch (t->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: make_room(&buf, &size, used + 64); used += sprintf(buf+used, "an array of %d ", (int)t->arrarg_const); break; case TN_POINTER_TO: { char *quali = ""; if (t->ptrarg != 0) { switch (t->ptrarg) { case TOK_KEY_VOLATILE: quali = "volatile"; break; case TOK_KEY_CONST: quali = "constant"; break; case TOK_KEY_RESTRICT: quali = "restricted"; break; } } make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a %s pointer to ", quali); break; } case TN_FUNCTION: make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a function (with %d args) returning ", t->tfunc->nargs); break; } } #if 0 p = basic_type_names[dt->code - TY_MIN]; #endif for (i = 0; basic_type_names[i].name != NULL; ++i) { if (dt->code == basic_type_names[i].code) { p = basic_type_names[i].name; break; } } make_room(&buf, &size, strlen(p) + 5); used += sprintf(buf+used, "%s", p); if (dt->code == TY_STRUCT) { if (dt->tstruc && dt->tstruc->tag) { make_room(&buf, &size, used + strlen(dt->tstruc->tag) + 2); sprintf(buf+used, " %s", dt->tstruc->tag); } } return buf; } #ifndef PREPROCESSOR extern void put_ppc_llong(struct num *); /* * XXX same stupid size_t cross-compilaion bug as const_from_value().. * this stuff SUCKS!!! */ struct token * const_from_type(struct type *ty, int from_alignment, int extype, struct token *t) { struct token *ret = alloc_token(); size_t size; int size_t_size; #if 0 ret->type = TY_ULONG; /* XXX size_t */ #endif ret->type = backend->get_size_t()->code; if (from_alignment) { size = backend->get_align_type(ty); } else { size = backend->get_sizeof_type(ty, t); } /*ret->data = n_xmemdup(&size, sizeof size);*/ ret->data = n_xmalloc(16); /* XXX */ size_t_size = backend->get_sizeof_type(backend->get_size_t(), NULL); if (sizeof size == size_t_size) { memcpy(ret->data, &size, sizeof size); } else if (sizeof(int) == size_t_size) { unsigned int i = (unsigned int)size; memcpy(ret->data, &i, sizeof i); } else if (sizeof(long) == size_t_size) { unsigned long l = (unsigned long)size; memcpy(ret->data, &l, sizeof l); } else if (sizeof(long long) == size_t_size) { unsigned long long ll = (unsigned long long)size; memcpy(ret->data, &ll, sizeof ll); } else { unimpl(); } if (backend->abi == ABI_POWER64 && extype != EXPR_CONST && extype != EXPR_CONSTINIT /* What about EXPR_OPTCONSTINIT?! */ ) { struct num *n = n_xmalloc(sizeof *n); /* * XXX see definition of put_ppc_llong() for an * explanation of this mess */ n->type = ret->type; n->value = ret->data; put_ppc_llong(n); /*ret->data = llong_const;*/ ret->data2 = llong_const; } return ret; } /* * XXX this interface is ROTTEN!! * too easy to pass a ``size_t'' for value with ty=NULL by accident!! * * XXXX WOAH this was totally broken WRT cross-compilation! ``type'' * is interpreted as host type when dealing with ``value'', and as * target type too by making it the type of the token! Current ad-hoc * kludge sucks! */ struct token * const_from_value(void *value, struct type *ty) { struct token *ret = alloc_token(); size_t size; if (ty == NULL) { ret->type = TY_INT; size = backend->get_sizeof_type(make_basic_type( TY_INT), NULL);; } else { ret->type = ty->code; size = backend->get_sizeof_type(ty, NULL); } if (ty && (IS_LONG(ty->code) || IS_LLONG(ty->code))) { if (sizeof(long) == size) { /* Size matches - nothing to do */ ; } else { static long long llv; llv = *(int *)value; value = &llv; } } ret->data = n_xmemdup(value, size); if (backend->abi == ABI_POWER64 && ty != NULL && is_integral_type(ty) && size == 8) { struct num *n = n_xmalloc(sizeof *n); static struct num nullnum; *n = nullnum; n->type = ret->type; n->value = ret->data; put_ppc_llong(n); ret->data2 = llong_const; } return ret; } /* * Construct a floating point constant token of type ``type'' * containing ``value'' (which must be a string parsable by sscanf().) */ struct token * fp_const_from_ascii(const char *value, int type) { struct num *n; struct token *ret = n_xmalloc(sizeof *ret); n = cross_scan_value(value, type, 0, 0, 1); if (n == NULL) { return NULL; } /* * XXX token.data is ``struct ty_float'', not * ``struct num''. Because the interfaces are * still messed up, we have to get the current * ty_float corresponding to ``n'' from the * float list. This SUCKS! */ ret->data = float_const/*n->value*/; ret->type = type; ret->ascii = n_xstrdup(value); return ret; } struct token * const_from_string(const char *value) { struct token *ret = alloc_token(); struct type *ty; struct ty_string *tmpstr; tmpstr = alloc_ty_string(); tmpstr->size = strlen(value) + 1; tmpstr->str = n_xmemdup(value, tmpstr->size); tmpstr->is_wide_char = 0; ret->type = TOK_STRING_LITERAL; ty = make_array_type(tmpstr->size, tmpstr->is_wide_char); tmpstr->ty = ty; ret->data = tmpstr; return ret; } int is_integral_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_CHAR(t->code) || IS_SHORT(t->code) || IS_INT(t->code) || IS_LONG(t->code) || IS_LLONG(t->code) || t->code == TY_ENUM) { return 1; } return 0; } int is_floating_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (t->code == TY_FLOAT || t->code == TY_DOUBLE || t->code == TY_LDOUBLE) { return 1; } return 0; } int is_arithmetic_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_FLOATING(t->code) || is_integral_type(t)) { return 1; } return 0; } int is_array_type(struct type *t) { struct type_node *tn; if (t->tlist == NULL) { return 0; } for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type != TN_ARRAY_OF) { return 0; } else { break; } } return 1; } int is_basic_agg_type(struct type *t) { if (t->tlist == NULL) { if (t->code == TY_STRUCT || t->code == TY_UNION) { return 1; } } else if (is_array_type(t)) { return 1; } return 0; } int is_scalar_type(struct type *t) { if (t->tlist == NULL && (t->code == TY_STRUCT || t->code == TY_UNION || t->code == TY_VOID)) { return 0; } return 1; } int is_arr_of_ptr(struct type *t) { struct type_node *tn; for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type == TN_POINTER_TO) { return 1; } else if (tn->type == TN_FUNCTION) { return 0; } } return 0; } int is_nullptr_const(struct token *constant, struct type *ty) { if (IS_INT(ty->code) && *(unsigned *)constant->data == 0) { return 1; } else if (IS_LONG(ty->code) && *(unsigned long *)constant->data == 0) { return 1; } return 0; } /* * The source type must be passed with a vreg because we need the null * pointer constant and object backing information it gives us */ int check_types_assign( struct token *t, struct type *left, struct vreg *right, int to_const_ok, int silent) { struct type *ltype = left; struct type *rtype = right->type; if (ltype == NULL || rtype == NULL) { printf("attempt to assign to/from value without type :(\n"); abort(); } /* * 01/26/08: Changed this to call is_modifyable(), which also * rules out assignment to const-qualified pointers */ /*if (ltype->tlist == NULL && ltype->is_const && !to_const_ok) { */ if (!is_modifyable(ltype) && !to_const_ok) { if (!silent) { errorfl(t, "Assignment to const-qualified object"); } return -1; } if (is_arithmetic_type(ltype)) { if (!is_arithmetic_type(rtype)) { if (ltype->code == TY_BOOL && rtype->tlist != NULL) { /* ok - pointer to bool */ return 0; } else { int allow = 0; if (rtype->tlist != NULL && is_integral_type(ltype)) { /* * 03/09/09: Give in and allow pointer * to integer assignment with a warning */ allow = 1; } if (!silent) { if (allow) { warningfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } else { errorfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } } if (allow) { return 0; } else { return -1; } } } else if (ltype->sign != rtype->sign && !right->from_const) { /* * Do not warn about signedness differences if the * right side is a constant! */ #if 0 /* XXX Too verbose */ warningfl(t, "Assignment from type of differing signedness"); #endif return 0; } return 0; } else if (ltype->tlist == NULL) { /* Must be struct/union */ if (rtype->tlist != NULL) { if (ltype->code == TY_BOOL) { return 0; } else { if (!silent) { /* 06/01/08: Warn, not error */ warningfl(t, "Assignment from pointer to non-pointer type"); } /* * 07/20/08: The return below was commented out! * That's wrong because pointer to struct will * compare assignable to struct * Why was this removed? */ return -1; } } else if (ltype->code == TY_BOOL) { return 0; /* _Bool b = ptr; is OK */ } else if (rtype->code != ltype->code || rtype->tstruc != ltype->tstruc) { if (!silent) { errorfl(t, "Assignment from incompatible type"); } return -1; } else { return 0; } } else { /* Left is pointer of some sort */ if (right->is_nullptr_const) { ; /* ok */ } else if (rtype->tlist == NULL) { if (!silent) { warningfl(t, "Assignment from non-pointer " "to pointer type"); } /* return -1;*/ } else if (rtype->code == TY_VOID && rtype->tlist->type == TN_POINTER_TO && rtype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (ltype->code == TY_VOID && ltype->tlist->type == TN_POINTER_TO && ltype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (compare_tlist(ltype->tlist, rtype->tlist, CMPTY_ARRAYPTR)) { if (!silent) { warningfl(t, "Assignment from incompatible pointer type" " (illegal in ISO C, and very " "probably not what you want)"); } else { /* * This is only used for transparent_union * right now... in that case we do not want * to allow this assignment because type- * checking is the whole point of that * language extension */ return -1; } return 0; } else if (!IS_CONST(ltype->flags) && IS_CONST(rtype->flags)) { if (!silent) { warningfl(t, "Assignment from const-qualified type " "to unqualified one"); } return 0; } else if (rtype->code != ltype->code && rtype->code != TY_VOID && ltype->code != TY_VOID /* XXX */ && (!IS_CHAR(ltype->code) || !IS_CHAR(rtype->code))) { if (type_without_sign(ltype->code) == type_without_sign(rtype->code)) { if (!silent) { warningfl(t, "Assignment from pointer of " "differing signedness"); } else { return -1; } return 0; } else { if (!silent) { warningfl(t, "Assignment from incompatible " "pointer type (illegal in ISO C, and " "very probably not what you want)"); } else { return -1; } #if 0 return -1; #endif return 0; } } else if (IS_CONST(ltype->flags) && !IS_CONST(rtype->flags) && ltype->tlist != NULL && ltype->tlist->next != NULL) { if (!silent) { warningfl(t, "ISO C does not allow assignment " "from `T **' to `const T **' without a " "cast (otherwise invalid code like " "`const char dont_modify; char *p; const " "char **cp = &p; *cp = &dont_modify; *p = 0;' " "would pass without warning)"); } return 0; } } return 0; } struct type * addrofify_type(struct type *ty) { struct type *ret = n_xmemdup(ty, sizeof *ty); struct type_node *tn; copy_tlist(&ret->tlist, ret->tlist); tn = alloc_type_node(); tn->type = TN_POINTER_TO; tn->next = ret->tlist; ret->tlist = tn; return ret; } int type_without_sign(int code) { int rc = code; if (code == TY_UCHAR) rc = TY_CHAR; else if (code == TY_USHORT) rc = TY_SHORT; else if (code == TY_UINT) rc = TY_INT; else if (code == TY_ULONG) rc = TY_LONG; else if (code == TY_ULLONG) rc = TY_LLONG; return rc; }
int stack_level(client_t *c) { int layer_level = (c->layer == LAYER_NORMAL ? 1 : (c->layer == LAYER_BELOW ? 0 : 2)); int state_level = (IS_TILED(c) ? 0 : (IS_FLOATING(c) ? 2 : 1)); return 3 * layer_level + state_level; }
bool is_floating (Value* self) { return IS_FLOATING(self); }
void grab_pointer(pointer_action_t pac) { PRINTF("grab pointer %u\n", pac); xcb_window_t win = XCB_NONE; xcb_point_t pos; query_pointer(&win, &pos); coordinates_t loc; if (locate_window(win, &loc)) { client_t *c = NULL; frozen_pointer->position = pos; frozen_pointer->action = pac; c = loc.node->client; frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; frozen_pointer->node = loc.node; frozen_pointer->client = c; frozen_pointer->window = c->window; frozen_pointer->horizontal_fence = NULL; frozen_pointer->vertical_fence = NULL; switch (pac) { case ACTION_FOCUS: if (loc.node != mon->desk->focus) { bool backup = pointer_follows_monitor; pointer_follows_monitor = false; focus_node(loc.monitor, loc.desktop, loc.node); pointer_follows_monitor = backup; } else if (focus_follows_pointer) { stack(loc.node, true); } frozen_pointer->action = ACTION_NONE; break; case ACTION_MOVE: case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (IS_FLOATING(c)) { frozen_pointer->rectangle = c->floating_rectangle; frozen_pointer->is_tiled = false; } else if (IS_TILED(c)) { frozen_pointer->rectangle = c->tiled_rectangle; frozen_pointer->is_tiled = (pac == ACTION_MOVE || c->state == STATE_PSEUDO_TILED); } else { frozen_pointer->action = ACTION_NONE; return; } if (pac == ACTION_RESIZE_SIDE) { float W = frozen_pointer->rectangle.width; float H = frozen_pointer->rectangle.height; float ratio = W / H; float x = pos.x - frozen_pointer->rectangle.x; float y = pos.y - frozen_pointer->rectangle.y; float diag_a = ratio * y; float diag_b = W - diag_a; if (x < diag_a) { if (x < diag_b) frozen_pointer->side = SIDE_LEFT; else frozen_pointer->side = SIDE_BOTTOM; } else { if (x < diag_b) frozen_pointer->side = SIDE_TOP; else frozen_pointer->side = SIDE_RIGHT; } } else if (pac == ACTION_RESIZE_CORNER) { int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2); int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2); if (pos.x > mid_x) { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_RIGHT; else frozen_pointer->corner = CORNER_TOP_RIGHT; } else { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_LEFT; else frozen_pointer->corner = CORNER_TOP_LEFT; } } if (frozen_pointer->is_tiled) { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); break; case SIDE_RIGHT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case SIDE_BOTTOM: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); break; case SIDE_LEFT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; case CORNER_TOP_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } if (frozen_pointer->horizontal_fence != NULL) frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio; if (frozen_pointer->vertical_fence != NULL) frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio; } break; case ACTION_NONE: break; } } else { if (pac == ACTION_FOCUS) { monitor_t *m = monitor_from_point(pos); if (m != NULL && m != mon) focus_node(m, m->desk, m->desk->focus); } frozen_pointer->action = ACTION_NONE; } }
void track_pointer(int root_x, int root_y) { if (frozen_pointer->action == ACTION_NONE) return; int delta_x, delta_y, x = 0, y = 0, w = 1, h = 1; pointer_action_t pac = frozen_pointer->action; monitor_t *m = frozen_pointer->monitor; desktop_t *d = frozen_pointer->desktop; node_t *n = frozen_pointer->node; client_t *c = frozen_pointer->client; xcb_window_t win = frozen_pointer->window; xcb_rectangle_t rect = frozen_pointer->rectangle; node_t *vertical_fence = frozen_pointer->vertical_fence; node_t *horizontal_fence = frozen_pointer->horizontal_fence; delta_x = root_x - frozen_pointer->position.x; delta_y = root_y - frozen_pointer->position.y; switch (pac) { case ACTION_MOVE: if (frozen_pointer->is_tiled) { xcb_window_t pwin = XCB_NONE; query_pointer(&pwin, NULL); if (pwin == win) return; coordinates_t loc; bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc)); if (is_managed && !IS_FLOATING(loc.node->client) && loc.monitor == m) { swap_nodes(m, d, n, m, d, loc.node); arrange(m, d); } else { if (is_managed && loc.monitor == m) { return; } else if (!is_managed) { xcb_point_t pt = (xcb_point_t) {root_x, root_y}; monitor_t *pmon = monitor_from_point(pt); if (pmon == NULL || pmon == m) { return; } else { loc.monitor = pmon; loc.desktop = pmon->desk; } } bool focused = (n == mon->desk->focus); transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus); if (focused) focus_node(loc.monitor, loc.desktop, n); frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; } } else { x = rect.x + delta_x; y = rect.y + delta_y; window_move(win, x, y); c->floating_rectangle.x = x; c->floating_rectangle.y = y; xcb_point_t pt = (xcb_point_t) {root_x, root_y}; monitor_t *pmon = monitor_from_point(pt); if (pmon == NULL || pmon == m) return; bool focused = (n == mon->desk->focus); transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus); if (focused) focus_node(pmon, pmon->desk, n); frozen_pointer->monitor = pmon; frozen_pointer->desktop = pmon->desk; } break; case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (frozen_pointer->is_tiled) { if (vertical_fence != NULL) { double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width; sr = MAX(0, sr); sr = MIN(1, sr); vertical_fence->split_ratio = sr; } if (horizontal_fence != NULL) { double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height; sr = MAX(0, sr); sr = MIN(1, sr); horizontal_fence->split_ratio = sr; } arrange(m, d); } else { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: x = rect.x; y = rect.y + delta_y; w = rect.width; h = rect.height - delta_y; break; case SIDE_RIGHT: x = rect.x; y = rect.y; w = rect.width + delta_x; h = rect.height; break; case SIDE_BOTTOM: x = rect.x; y = rect.y; w = rect.width; h = rect.height + delta_y; break; case SIDE_LEFT: x = rect.x + delta_x; y = rect.y; w = rect.width - delta_x; h = rect.height; break; } } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: x = rect.x + delta_x; y = rect.y + delta_y; w = rect.width - delta_x; h = rect.height - delta_y; break; case CORNER_TOP_RIGHT: x = rect.x; y = rect.y + delta_y; w = rect.width + delta_x; h = rect.height - delta_y; break; case CORNER_BOTTOM_LEFT: x = rect.x + delta_x; y = rect.y; w = rect.width - delta_x; h = rect.height + delta_y; break; case CORNER_BOTTOM_RIGHT: x = rect.x; y = rect.y; w = rect.width + delta_x; h = rect.height + delta_y; break; } } int oldw = w, oldh = h; restrain_floating_size(c, &w, &h); if (c->state == STATE_FLOATING) { if (oldw == w) { c->floating_rectangle.x = x; c->floating_rectangle.width = w; } if (oldh == h) { c->floating_rectangle.y = y; c->floating_rectangle.height = h; } window_move_resize(win, c->floating_rectangle.x, c->floating_rectangle.y, c->floating_rectangle.width, c->floating_rectangle.height); } else { c->floating_rectangle.width = w; c->floating_rectangle.height = h; arrange(m, d); } } break; case ACTION_FOCUS: case ACTION_NONE: break; } }
void configure_request(xcb_generic_event_t *evt) { xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt; coordinates_t loc; bool is_managed = locate_window(e->window, &loc); client_t *c = (is_managed ? loc.node->client : NULL); int w = 0, h = 0; if (is_managed && !IS_FLOATING(c)) { if (e->value_mask & XCB_CONFIG_WINDOW_X) { c->floating_rectangle.x = e->x; } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { c->floating_rectangle.y = e->y; } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { w = e->width; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { h = e->height; } if (w != 0) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } if (h != 0) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } xcb_configure_notify_event_t evt; unsigned int bw = c->border_width; xcb_rectangle_t rect = get_rectangle(loc.desktop, loc.node); evt.response_type = XCB_CONFIGURE_NOTIFY; evt.event = e->window; evt.window = e->window; evt.above_sibling = XCB_NONE; evt.x = rect.x; evt.y = rect.y; evt.width = rect.width; evt.height = rect.height; evt.border_width = bw; evt.override_redirect = false; xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt); if (c->state == STATE_PSEUDO_TILED) { arrange(loc.monitor, loc.desktop); } } else { uint16_t mask = 0; uint32_t values[7]; unsigned short i = 0; if (e->value_mask & XCB_CONFIG_WINDOW_X) { mask |= XCB_CONFIG_WINDOW_X; values[i++] = e->x; if (is_managed) { c->floating_rectangle.x = e->x; } } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { mask |= XCB_CONFIG_WINDOW_Y; values[i++] = e->y; if (is_managed) { c->floating_rectangle.y = e->y; } } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { mask |= XCB_CONFIG_WINDOW_WIDTH; w = e->width; if (is_managed) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } values[i++] = w; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { mask |= XCB_CONFIG_WINDOW_HEIGHT; h = e->height; if (is_managed) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } values[i++] = h; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; values[i++] = e->border_width; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { mask |= XCB_CONFIG_WINDOW_SIBLING; values[i++] = e->sibling; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { mask |= XCB_CONFIG_WINDOW_STACK_MODE; values[i++] = e->stack_mode; } xcb_configure_window(dpy, e->window, mask, values); if (is_managed && mask & XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT) { xcb_rectangle_t r = c->floating_rectangle; put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%X 0x%X 0x%X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y); } } if (is_managed) { monitor_t *m = monitor_from_client(c); adapt_geometry(&m->rectangle, &loc.monitor->rectangle, loc.node); } }